@@ -0,0 +1,28 @@
|
|||||||
|
import api from './index.js'
|
||||||
|
|
||||||
|
export const customerApi = {
|
||||||
|
// 客户列表
|
||||||
|
list(params = {}) {
|
||||||
|
return api.post('/customer/list', params)
|
||||||
|
},
|
||||||
|
|
||||||
|
// 客户详情
|
||||||
|
get(id) {
|
||||||
|
return api.post('/customer/get', { id })
|
||||||
|
},
|
||||||
|
|
||||||
|
// 新增客户
|
||||||
|
add(data) {
|
||||||
|
return api.post('/customer/add', data)
|
||||||
|
},
|
||||||
|
|
||||||
|
// 编辑客户
|
||||||
|
update(data) {
|
||||||
|
return api.post('/customer/update', data)
|
||||||
|
},
|
||||||
|
|
||||||
|
// 删除客户
|
||||||
|
delete(id) {
|
||||||
|
return api.post('/customer/delete', { id })
|
||||||
|
}
|
||||||
|
}
|
||||||
+2
-2
@@ -2,8 +2,8 @@
|
|||||||
"name" : "Operations",
|
"name" : "Operations",
|
||||||
"appid" : "__UNI__8A0DE5E",
|
"appid" : "__UNI__8A0DE5E",
|
||||||
"description" : "Operations(运营)的缩写,一个前后端分离的工作流/运营管理系统。",
|
"description" : "Operations(运营)的缩写,一个前后端分离的工作流/运营管理系统。",
|
||||||
"versionName" : "1.3.3",
|
"versionName" : "1.4.3",
|
||||||
"versionCode" : "133",
|
"versionCode" : "143",
|
||||||
"transformPx" : false,
|
"transformPx" : false,
|
||||||
"app-plus" : {
|
"app-plus" : {
|
||||||
"usingComponents" : true,
|
"usingComponents" : true,
|
||||||
|
|||||||
@@ -34,6 +34,50 @@
|
|||||||
<text class="form-label">备注</text>
|
<text class="form-label">备注</text>
|
||||||
<textarea class="form-textarea" v-model="form.remark" placeholder="请输入备注(选填)" />
|
<textarea class="form-textarea" v-model="form.remark" placeholder="请输入备注(选填)" />
|
||||||
</view>
|
</view>
|
||||||
|
|
||||||
|
<!-- 关联客户 -->
|
||||||
|
<view class="form-item">
|
||||||
|
<text class="form-label">关联客户</text>
|
||||||
|
|
||||||
|
<!-- 已选中的客户 -->
|
||||||
|
<view v-if="selectedCustomers.length > 0" class="selected-customers">
|
||||||
|
<view
|
||||||
|
v-for="customer in selectedCustomers"
|
||||||
|
:key="customer.id"
|
||||||
|
class="customer-tag"
|
||||||
|
>
|
||||||
|
<text>{{ (customer.last_name || '') + (customer.first_name ? ' ' + customer.first_name : '') }}</text>
|
||||||
|
<text class="customer-tag-remove" @click="removeCustomer(customer.id)">×</text>
|
||||||
|
</view>
|
||||||
|
</view>
|
||||||
|
|
||||||
|
<!-- 搜索框 -->
|
||||||
|
<view class="customer-search-box">
|
||||||
|
<input
|
||||||
|
class="customer-search-input"
|
||||||
|
v-model="customerSearchQuery"
|
||||||
|
placeholder="搜索客户..."
|
||||||
|
@input="onCustomerSearchInput"
|
||||||
|
@focus="onCustomerSearchFocus"
|
||||||
|
/>
|
||||||
|
</view>
|
||||||
|
|
||||||
|
<!-- 搜索结果 -->
|
||||||
|
<view v-if="showCustomerDropdown && customerSearchResults.length > 0" class="customer-dropdown">
|
||||||
|
<view
|
||||||
|
v-for="customer in customerSearchResults"
|
||||||
|
:key="customer.id"
|
||||||
|
class="customer-dropdown-item"
|
||||||
|
@click="selectCustomer(customer)"
|
||||||
|
>
|
||||||
|
<text class="customer-dropdown-name">{{ (customer.last_name || '') + (customer.first_name ? ' ' + customer.first_name : '') }}</text>
|
||||||
|
<text v-if="customer.primary_phone" class="customer-dropdown-phone">{{ customer.primary_phone }}</text>
|
||||||
|
</view>
|
||||||
|
</view>
|
||||||
|
<view v-else-if="showCustomerDropdown && customerSearchQuery && customerSearchResults.length === 0 && !customerSearchLoading" class="customer-dropdown-empty">
|
||||||
|
未找到匹配的客户
|
||||||
|
</view>
|
||||||
|
</view>
|
||||||
</view>
|
</view>
|
||||||
|
|
||||||
<view class="form-card">
|
<view class="form-card">
|
||||||
@@ -68,6 +112,7 @@
|
|||||||
<script setup>
|
<script setup>
|
||||||
import { ref } from 'vue'
|
import { ref } from 'vue'
|
||||||
import { warehouseApi } from '@/api/warehouse.js'
|
import { warehouseApi } from '@/api/warehouse.js'
|
||||||
|
import { customerApi } from '@/api/customer.js'
|
||||||
import { useConfigStore } from '@/stores/config.js'
|
import { useConfigStore } from '@/stores/config.js'
|
||||||
import api from '@/api/index.js'
|
import api from '@/api/index.js'
|
||||||
|
|
||||||
@@ -85,6 +130,14 @@ const form = ref({
|
|||||||
photos: []
|
photos: []
|
||||||
})
|
})
|
||||||
|
|
||||||
|
// 关联客户
|
||||||
|
const selectedCustomers = ref([])
|
||||||
|
const customerSearchQuery = ref('')
|
||||||
|
const customerSearchResults = ref([])
|
||||||
|
const showCustomerDropdown = ref(false)
|
||||||
|
const customerSearchLoading = ref(false)
|
||||||
|
let customerSearchTimer = null
|
||||||
|
|
||||||
function getPhotoUrl(sha256) {
|
function getPhotoUrl(sha256) {
|
||||||
const baseUrl = configStore.getFileBaseUrl ? configStore.getFileBaseUrl() : ''
|
const baseUrl = configStore.getFileBaseUrl ? configStore.getFileBaseUrl() : ''
|
||||||
return `${baseUrl}/api/files/get/${sha256}`
|
return `${baseUrl}/api/files/get/${sha256}`
|
||||||
@@ -131,6 +184,57 @@ function removePhoto(index) {
|
|||||||
form.value.photos.splice(index, 1)
|
form.value.photos.splice(index, 1)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// 客户搜索
|
||||||
|
async function searchCustomers() {
|
||||||
|
if (!customerSearchQuery.value.trim()) {
|
||||||
|
customerSearchResults.value = []
|
||||||
|
return
|
||||||
|
}
|
||||||
|
customerSearchLoading.value = true
|
||||||
|
try {
|
||||||
|
const res = await customerApi.list(1, 20, customerSearchQuery.value)
|
||||||
|
if (res.errCode === 0 && res.data) {
|
||||||
|
customerSearchResults.value = res.data.customers || res.data || []
|
||||||
|
} else {
|
||||||
|
customerSearchResults.value = []
|
||||||
|
}
|
||||||
|
} catch (e) {
|
||||||
|
console.error('搜索客户失败', e)
|
||||||
|
customerSearchResults.value = []
|
||||||
|
} finally {
|
||||||
|
customerSearchLoading.value = false
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
function onCustomerSearchInput() {
|
||||||
|
clearTimeout(customerSearchTimer)
|
||||||
|
customerSearchTimer = setTimeout(() => {
|
||||||
|
searchCustomers()
|
||||||
|
}, 300)
|
||||||
|
}
|
||||||
|
|
||||||
|
function onCustomerSearchFocus() {
|
||||||
|
showCustomerDropdown.value = true
|
||||||
|
searchCustomers()
|
||||||
|
}
|
||||||
|
|
||||||
|
function selectCustomer(customer) {
|
||||||
|
const exists = selectedCustomers.value.find(c => c.id === customer.id)
|
||||||
|
if (!exists) {
|
||||||
|
selectedCustomers.value.push(customer)
|
||||||
|
}
|
||||||
|
customerSearchQuery.value = ''
|
||||||
|
showCustomerDropdown.value = false
|
||||||
|
customerSearchResults.value = []
|
||||||
|
}
|
||||||
|
|
||||||
|
function removeCustomer(id) {
|
||||||
|
const index = selectedCustomers.value.findIndex(c => c.id === id)
|
||||||
|
if (index >= 0) {
|
||||||
|
selectedCustomers.value.splice(index, 1)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
async function submitForm() {
|
async function submitForm() {
|
||||||
if (!form.value.name.trim()) {
|
if (!form.value.name.trim()) {
|
||||||
uni.showToast({ title: '请输入名称', icon: 'none' })
|
uni.showToast({ title: '请输入名称', icon: 'none' })
|
||||||
@@ -145,7 +249,8 @@ async function submitForm() {
|
|||||||
remark: form.value.remark,
|
remark: form.value.remark,
|
||||||
quantity: form.value.quantity > 0 ? form.value.quantity : 1,
|
quantity: form.value.quantity > 0 ? form.value.quantity : 1,
|
||||||
container_id: containerId.value || null,
|
container_id: containerId.value || null,
|
||||||
photos: form.value.photos
|
photos: form.value.photos,
|
||||||
|
customer_ids: selectedCustomers.value.map(c => c.id)
|
||||||
}
|
}
|
||||||
|
|
||||||
const res = await warehouseApi.addItem(data)
|
const res = await warehouseApi.addItem(data)
|
||||||
@@ -359,4 +464,91 @@ onLoad((options) => {
|
|||||||
margin: 0 16rpx;
|
margin: 0 16rpx;
|
||||||
box-sizing: border-box;
|
box-sizing: border-box;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* 关联客户 */
|
||||||
|
.selected-customers {
|
||||||
|
display: flex;
|
||||||
|
flex-wrap: wrap;
|
||||||
|
gap: 12rpx;
|
||||||
|
margin-bottom: 16rpx;
|
||||||
|
}
|
||||||
|
|
||||||
|
.customer-tag {
|
||||||
|
display: inline-flex;
|
||||||
|
align-items: center;
|
||||||
|
gap: 8rpx;
|
||||||
|
padding: 8rpx 16rpx;
|
||||||
|
background-color: #e6f7ff;
|
||||||
|
border: 1rpx solid #91d5ff;
|
||||||
|
border-radius: 20rpx;
|
||||||
|
font-size: 24rpx;
|
||||||
|
color: #1890ff;
|
||||||
|
}
|
||||||
|
|
||||||
|
.customer-tag-remove {
|
||||||
|
font-size: 28rpx;
|
||||||
|
color: #999;
|
||||||
|
margin-left: 4rpx;
|
||||||
|
}
|
||||||
|
|
||||||
|
.customer-tag-remove:active {
|
||||||
|
color: #f56c6c;
|
||||||
|
}
|
||||||
|
|
||||||
|
.customer-search-box {
|
||||||
|
margin-top: 12rpx;
|
||||||
|
}
|
||||||
|
|
||||||
|
.customer-search-input {
|
||||||
|
width: 100%;
|
||||||
|
height: 72rpx;
|
||||||
|
padding: 0 20rpx;
|
||||||
|
background-color: #f5f5f5;
|
||||||
|
border-radius: 10rpx;
|
||||||
|
font-size: 28rpx;
|
||||||
|
box-sizing: border-box;
|
||||||
|
}
|
||||||
|
|
||||||
|
.customer-dropdown {
|
||||||
|
margin-top: 12rpx;
|
||||||
|
background-color: #fff;
|
||||||
|
border: 1rpx solid #eee;
|
||||||
|
border-radius: 10rpx;
|
||||||
|
max-height: 400rpx;
|
||||||
|
overflow-y: auto;
|
||||||
|
}
|
||||||
|
|
||||||
|
.customer-dropdown-item {
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
padding: 20rpx;
|
||||||
|
border-bottom: 1rpx solid #f0f0f0;
|
||||||
|
}
|
||||||
|
|
||||||
|
.customer-dropdown-item:last-child {
|
||||||
|
border-bottom: none;
|
||||||
|
}
|
||||||
|
|
||||||
|
.customer-dropdown-item:active {
|
||||||
|
background-color: #f5f5f5;
|
||||||
|
}
|
||||||
|
|
||||||
|
.customer-dropdown-name {
|
||||||
|
flex: 1;
|
||||||
|
font-size: 28rpx;
|
||||||
|
color: #333;
|
||||||
|
}
|
||||||
|
|
||||||
|
.customer-dropdown-phone {
|
||||||
|
font-size: 24rpx;
|
||||||
|
color: #999;
|
||||||
|
margin-left: 16rpx;
|
||||||
|
}
|
||||||
|
|
||||||
|
.customer-dropdown-empty {
|
||||||
|
padding: 30rpx;
|
||||||
|
text-align: center;
|
||||||
|
color: #999;
|
||||||
|
font-size: 26rpx;
|
||||||
|
}
|
||||||
</style>
|
</style>
|
||||||
|
|||||||
@@ -110,6 +110,23 @@
|
|||||||
<text class="wo-status" :class="wo.status">{{ getWorkOrderStatusText(wo.status) }}</text>
|
<text class="wo-status" :class="wo.status">{{ getWorkOrderStatusText(wo.status) }}</text>
|
||||||
</view>
|
</view>
|
||||||
</view>
|
</view>
|
||||||
|
|
||||||
|
<!-- 关联客户 -->
|
||||||
|
<view class="card" v-if="linkedCustomers.length > 0">
|
||||||
|
<view class="card-header">
|
||||||
|
<text class="card-title">关联客户</text>
|
||||||
|
</view>
|
||||||
|
<view class="linked-customers">
|
||||||
|
<view
|
||||||
|
class="linked-customer-item"
|
||||||
|
v-for="customer in linkedCustomers"
|
||||||
|
:key="customer.ID"
|
||||||
|
>
|
||||||
|
<text class="customer-name">{{ (customer.last_name || '') + (customer.first_name ? ' ' + customer.first_name : '') }}</text>
|
||||||
|
<text v-if="customer.title" class="customer-title">{{ customer.title }}</text>
|
||||||
|
</view>
|
||||||
|
</view>
|
||||||
|
</view>
|
||||||
</view>
|
</view>
|
||||||
|
|
||||||
<!-- 空状态 -->
|
<!-- 空状态 -->
|
||||||
@@ -179,6 +196,7 @@ const item = ref(null)
|
|||||||
const photos = ref([])
|
const photos = ref([])
|
||||||
const commits = ref([])
|
const commits = ref([])
|
||||||
const workOrders = ref([])
|
const workOrders = ref([])
|
||||||
|
const linkedCustomers = ref([])
|
||||||
const canModify = ref(false)
|
const canModify = ref(false)
|
||||||
|
|
||||||
// 移动相关
|
// 移动相关
|
||||||
@@ -230,6 +248,7 @@ async function fetchDetail() {
|
|||||||
photos.value = res.data.photos || []
|
photos.value = res.data.photos || []
|
||||||
commits.value = res.data.commits || []
|
commits.value = res.data.commits || []
|
||||||
workOrders.value = res.data.work_orders || []
|
workOrders.value = res.data.work_orders || []
|
||||||
|
linkedCustomers.value = res.data.customers || []
|
||||||
canModify.value = res.data.canModifyItem
|
canModify.value = res.data.canModifyItem
|
||||||
} else {
|
} else {
|
||||||
uni.showToast({ title: '获取详情失败', icon: 'none' })
|
uni.showToast({ title: '获取详情失败', icon: 'none' })
|
||||||
@@ -315,6 +334,18 @@ function addWorkOrder() {
|
|||||||
: item.value.Name,
|
: item.value.Name,
|
||||||
description: item.value.Remark || '',
|
description: item.value.Remark || '',
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// 如果有已关联的客户,自动填充到工单
|
||||||
|
if (linkedCustomers.value && linkedCustomers.value.length > 0) {
|
||||||
|
prefillData.customer_ids = linkedCustomers.value.map(c => c.ID)
|
||||||
|
prefillData.customers = linkedCustomers.value.map(c => ({
|
||||||
|
id: c.ID,
|
||||||
|
first_name: c.first_name || '',
|
||||||
|
last_name: c.last_name || '',
|
||||||
|
primary_phone: c.primary_phone || ''
|
||||||
|
}))
|
||||||
|
}
|
||||||
|
|
||||||
uni.setStorageSync('prefill_work_order', JSON.stringify(prefillData))
|
uni.setStorageSync('prefill_work_order', JSON.stringify(prefillData))
|
||||||
uni.navigateTo({
|
uni.navigateTo({
|
||||||
url: '/pages/workorder/add-workorder'
|
url: '/pages/workorder/add-workorder'
|
||||||
@@ -642,6 +673,33 @@ onShow(() => {
|
|||||||
color: #ff575a;
|
color: #ff575a;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.linked-customers {
|
||||||
|
padding: 20rpx 30rpx;
|
||||||
|
}
|
||||||
|
|
||||||
|
.linked-customer-item {
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
padding: 16rpx 0;
|
||||||
|
border-bottom: 1rpx solid #f5f5f5;
|
||||||
|
}
|
||||||
|
|
||||||
|
.linked-customer-item:last-child {
|
||||||
|
border-bottom: none;
|
||||||
|
}
|
||||||
|
|
||||||
|
.customer-name {
|
||||||
|
font-size: 28rpx;
|
||||||
|
color: #333;
|
||||||
|
flex: 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
.customer-title {
|
||||||
|
font-size: 24rpx;
|
||||||
|
color: #999;
|
||||||
|
margin-left: 16rpx;
|
||||||
|
}
|
||||||
|
|
||||||
.action-bar {
|
.action-bar {
|
||||||
position: fixed;
|
position: fixed;
|
||||||
bottom: 0;
|
bottom: 0;
|
||||||
|
|||||||
@@ -39,6 +39,50 @@
|
|||||||
<text class="form-label">备注</text>
|
<text class="form-label">备注</text>
|
||||||
<textarea class="form-textarea" v-model="form.remark" placeholder="请输入备注(选填)" />
|
<textarea class="form-textarea" v-model="form.remark" placeholder="请输入备注(选填)" />
|
||||||
</view>
|
</view>
|
||||||
|
|
||||||
|
<!-- 关联客户 -->
|
||||||
|
<view class="form-item">
|
||||||
|
<text class="form-label">关联客户</text>
|
||||||
|
|
||||||
|
<!-- 已选中的客户 -->
|
||||||
|
<view v-if="selectedCustomers.length > 0" class="selected-customers">
|
||||||
|
<view
|
||||||
|
v-for="customer in selectedCustomers"
|
||||||
|
:key="customer.id"
|
||||||
|
class="customer-tag"
|
||||||
|
>
|
||||||
|
<text>{{ (customer.last_name || '') + (customer.first_name ? ' ' + customer.first_name : '') }}</text>
|
||||||
|
<text class="customer-tag-remove" @click="removeCustomer(customer.id)">×</text>
|
||||||
|
</view>
|
||||||
|
</view>
|
||||||
|
|
||||||
|
<!-- 搜索框 -->
|
||||||
|
<view class="customer-search-box">
|
||||||
|
<input
|
||||||
|
class="customer-search-input"
|
||||||
|
v-model="customerSearchQuery"
|
||||||
|
placeholder="搜索客户..."
|
||||||
|
@input="onCustomerSearchInput"
|
||||||
|
@focus="onCustomerSearchFocus"
|
||||||
|
/>
|
||||||
|
</view>
|
||||||
|
|
||||||
|
<!-- 搜索结果 -->
|
||||||
|
<view v-if="showCustomerDropdown && customerSearchResults.length > 0" class="customer-dropdown">
|
||||||
|
<view
|
||||||
|
v-for="customer in customerSearchResults"
|
||||||
|
:key="customer.id"
|
||||||
|
class="customer-dropdown-item"
|
||||||
|
@click="selectCustomer(customer)"
|
||||||
|
>
|
||||||
|
<text class="customer-dropdown-name">{{ (customer.last_name || '') + (customer.first_name ? ' ' + customer.first_name : '') }}</text>
|
||||||
|
<text v-if="customer.primary_phone" class="customer-dropdown-phone">{{ customer.primary_phone }}</text>
|
||||||
|
</view>
|
||||||
|
</view>
|
||||||
|
<view v-else-if="showCustomerDropdown && customerSearchQuery && customerSearchResults.length === 0 && !customerSearchLoading" class="customer-dropdown-empty">
|
||||||
|
未找到匹配的客户
|
||||||
|
</view>
|
||||||
|
</view>
|
||||||
</view>
|
</view>
|
||||||
|
|
||||||
<view class="form-card">
|
<view class="form-card">
|
||||||
@@ -74,6 +118,7 @@
|
|||||||
<script setup>
|
<script setup>
|
||||||
import { ref } from 'vue'
|
import { ref } from 'vue'
|
||||||
import { warehouseApi } from '@/api/warehouse.js'
|
import { warehouseApi } from '@/api/warehouse.js'
|
||||||
|
import { customerApi } from '@/api/customer.js'
|
||||||
import { useConfigStore } from '@/stores/config.js'
|
import { useConfigStore } from '@/stores/config.js'
|
||||||
import api from '@/api/index.js'
|
import api from '@/api/index.js'
|
||||||
|
|
||||||
@@ -92,6 +137,14 @@ const form = ref({
|
|||||||
photos: []
|
photos: []
|
||||||
})
|
})
|
||||||
|
|
||||||
|
// 关联客户
|
||||||
|
const selectedCustomers = ref([])
|
||||||
|
const customerSearchQuery = ref('')
|
||||||
|
const customerSearchResults = ref([])
|
||||||
|
const showCustomerDropdown = ref(false)
|
||||||
|
const customerSearchLoading = ref(false)
|
||||||
|
let customerSearchTimer = null
|
||||||
|
|
||||||
function getPhotoUrl(sha256) {
|
function getPhotoUrl(sha256) {
|
||||||
const baseUrl = configStore.getFileBaseUrl ? configStore.getFileBaseUrl() : ''
|
const baseUrl = configStore.getFileBaseUrl ? configStore.getFileBaseUrl() : ''
|
||||||
return `${baseUrl}/api/files/get/${sha256}`
|
return `${baseUrl}/api/files/get/${sha256}`
|
||||||
@@ -138,6 +191,57 @@ function removePhoto(index) {
|
|||||||
form.value.photos.splice(index, 1)
|
form.value.photos.splice(index, 1)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// 客户搜索
|
||||||
|
async function searchCustomers() {
|
||||||
|
if (!customerSearchQuery.value.trim()) {
|
||||||
|
customerSearchResults.value = []
|
||||||
|
return
|
||||||
|
}
|
||||||
|
customerSearchLoading.value = true
|
||||||
|
try {
|
||||||
|
const res = await customerApi.list(1, 20, customerSearchQuery.value)
|
||||||
|
if (res.errCode === 0 && res.data) {
|
||||||
|
customerSearchResults.value = res.data.customers || res.data || []
|
||||||
|
} else {
|
||||||
|
customerSearchResults.value = []
|
||||||
|
}
|
||||||
|
} catch (e) {
|
||||||
|
console.error('搜索客户失败', e)
|
||||||
|
customerSearchResults.value = []
|
||||||
|
} finally {
|
||||||
|
customerSearchLoading.value = false
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
function onCustomerSearchInput() {
|
||||||
|
clearTimeout(customerSearchTimer)
|
||||||
|
customerSearchTimer = setTimeout(() => {
|
||||||
|
searchCustomers()
|
||||||
|
}, 300)
|
||||||
|
}
|
||||||
|
|
||||||
|
function onCustomerSearchFocus() {
|
||||||
|
showCustomerDropdown.value = true
|
||||||
|
searchCustomers()
|
||||||
|
}
|
||||||
|
|
||||||
|
function selectCustomer(customer) {
|
||||||
|
const exists = selectedCustomers.value.find(c => c.id === customer.id)
|
||||||
|
if (!exists) {
|
||||||
|
selectedCustomers.value.push(customer)
|
||||||
|
}
|
||||||
|
customerSearchQuery.value = ''
|
||||||
|
showCustomerDropdown.value = false
|
||||||
|
customerSearchResults.value = []
|
||||||
|
}
|
||||||
|
|
||||||
|
function removeCustomer(id) {
|
||||||
|
const index = selectedCustomers.value.findIndex(c => c.id === id)
|
||||||
|
if (index >= 0) {
|
||||||
|
selectedCustomers.value.splice(index, 1)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
async function fetchDetail() {
|
async function fetchDetail() {
|
||||||
loading.value = true
|
loading.value = true
|
||||||
try {
|
try {
|
||||||
@@ -151,6 +255,11 @@ async function fetchDetail() {
|
|||||||
quantity: item.Quantity ?? 1,
|
quantity: item.Quantity ?? 1,
|
||||||
photos: res.data.photos ? res.data.photos.map(p => p.Sha256) : []
|
photos: res.data.photos ? res.data.photos.map(p => p.Sha256) : []
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// 加载已关联的客户
|
||||||
|
if (res.data.customers && res.data.customers.length > 0) {
|
||||||
|
selectedCustomers.value = res.data.customers
|
||||||
|
}
|
||||||
} else {
|
} else {
|
||||||
uni.showToast({ title: '获取详情失败', icon: 'none' })
|
uni.showToast({ title: '获取详情失败', icon: 'none' })
|
||||||
}
|
}
|
||||||
@@ -176,7 +285,8 @@ async function submitForm() {
|
|||||||
serial_number: form.value.serialNumber,
|
serial_number: form.value.serialNumber,
|
||||||
remark: form.value.remark,
|
remark: form.value.remark,
|
||||||
quantity: form.value.quantity > 0 ? form.value.quantity : 1,
|
quantity: form.value.quantity > 0 ? form.value.quantity : 1,
|
||||||
photos: form.value.photos
|
photos: form.value.photos,
|
||||||
|
customer_ids: selectedCustomers.value.map(c => c.id)
|
||||||
}
|
}
|
||||||
|
|
||||||
const res = await warehouseApi.updateItem(data)
|
const res = await warehouseApi.updateItem(data)
|
||||||
@@ -397,4 +507,91 @@ onLoad((options) => {
|
|||||||
margin: 0 16rpx;
|
margin: 0 16rpx;
|
||||||
box-sizing: border-box;
|
box-sizing: border-box;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* 关联客户 */
|
||||||
|
.selected-customers {
|
||||||
|
display: flex;
|
||||||
|
flex-wrap: wrap;
|
||||||
|
gap: 12rpx;
|
||||||
|
margin-bottom: 16rpx;
|
||||||
|
}
|
||||||
|
|
||||||
|
.customer-tag {
|
||||||
|
display: inline-flex;
|
||||||
|
align-items: center;
|
||||||
|
gap: 8rpx;
|
||||||
|
padding: 8rpx 16rpx;
|
||||||
|
background-color: #e6f7ff;
|
||||||
|
border: 1rpx solid #91d5ff;
|
||||||
|
border-radius: 20rpx;
|
||||||
|
font-size: 24rpx;
|
||||||
|
color: #1890ff;
|
||||||
|
}
|
||||||
|
|
||||||
|
.customer-tag-remove {
|
||||||
|
font-size: 28rpx;
|
||||||
|
color: #999;
|
||||||
|
margin-left: 4rpx;
|
||||||
|
}
|
||||||
|
|
||||||
|
.customer-tag-remove:active {
|
||||||
|
color: #f56c6c;
|
||||||
|
}
|
||||||
|
|
||||||
|
.customer-search-box {
|
||||||
|
margin-top: 12rpx;
|
||||||
|
}
|
||||||
|
|
||||||
|
.customer-search-input {
|
||||||
|
width: 100%;
|
||||||
|
height: 72rpx;
|
||||||
|
padding: 0 20rpx;
|
||||||
|
background-color: #f5f5f5;
|
||||||
|
border-radius: 10rpx;
|
||||||
|
font-size: 28rpx;
|
||||||
|
box-sizing: border-box;
|
||||||
|
}
|
||||||
|
|
||||||
|
.customer-dropdown {
|
||||||
|
margin-top: 12rpx;
|
||||||
|
background-color: #fff;
|
||||||
|
border: 1rpx solid #eee;
|
||||||
|
border-radius: 10rpx;
|
||||||
|
max-height: 400rpx;
|
||||||
|
overflow-y: auto;
|
||||||
|
}
|
||||||
|
|
||||||
|
.customer-dropdown-item {
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
padding: 20rpx;
|
||||||
|
border-bottom: 1rpx solid #f0f0f0;
|
||||||
|
}
|
||||||
|
|
||||||
|
.customer-dropdown-item:last-child {
|
||||||
|
border-bottom: none;
|
||||||
|
}
|
||||||
|
|
||||||
|
.customer-dropdown-item:active {
|
||||||
|
background-color: #f5f5f5;
|
||||||
|
}
|
||||||
|
|
||||||
|
.customer-dropdown-name {
|
||||||
|
flex: 1;
|
||||||
|
font-size: 28rpx;
|
||||||
|
color: #333;
|
||||||
|
}
|
||||||
|
|
||||||
|
.customer-dropdown-phone {
|
||||||
|
font-size: 24rpx;
|
||||||
|
color: #999;
|
||||||
|
margin-left: 16rpx;
|
||||||
|
}
|
||||||
|
|
||||||
|
.customer-dropdown-empty {
|
||||||
|
padding: 30rpx;
|
||||||
|
text-align: center;
|
||||||
|
color: #999;
|
||||||
|
font-size: 26rpx;
|
||||||
|
}
|
||||||
</style>
|
</style>
|
||||||
|
|||||||
@@ -36,16 +36,22 @@
|
|||||||
<text class="form-label">关联物品</text>
|
<text class="form-label">关联物品</text>
|
||||||
|
|
||||||
<!-- 已选择物品 -->
|
<!-- 已选择物品 -->
|
||||||
<view v-if="selectedItem" class="selected-item">
|
<view v-if="selectedItems.length > 0" class="selected-items">
|
||||||
<view class="selected-item-info">
|
<view
|
||||||
<text class="selected-item-name">{{ selectedItem.Name }}</text>
|
v-for="item in selectedItems"
|
||||||
<text v-if="selectedItem.SerialNumber" class="selected-item-serial">{{ selectedItem.SerialNumber }}</text>
|
:key="item.ID"
|
||||||
|
class="selected-item-tag"
|
||||||
|
>
|
||||||
|
<view class="selected-item-tag-info">
|
||||||
|
<text class="selected-item-tag-name">{{ item.Name }}</text>
|
||||||
|
<text v-if="item.SerialNumber" class="selected-item-tag-serial">{{ item.SerialNumber }}</text>
|
||||||
|
</view>
|
||||||
|
<text class="remove-item" @click="removeSelectedItem(item.ID)">×</text>
|
||||||
</view>
|
</view>
|
||||||
<text class="clear-btn" @click="clearSelectedItem">清除</text>
|
|
||||||
</view>
|
</view>
|
||||||
|
|
||||||
<!-- 搜索框 -->
|
<!-- 搜索框 -->
|
||||||
<view v-else class="search-box">
|
<view class="search-box">
|
||||||
<input
|
<input
|
||||||
v-model="searchQuery"
|
v-model="searchQuery"
|
||||||
class="form-input"
|
class="form-input"
|
||||||
@@ -63,8 +69,10 @@
|
|||||||
class="dropdown-item"
|
class="dropdown-item"
|
||||||
@click="selectItem(item)"
|
@click="selectItem(item)"
|
||||||
>
|
>
|
||||||
<text class="dropdown-name">{{ item.Name }}</text>
|
<view class="dropdown-item-info">
|
||||||
<text v-if="item.SerialNumber" class="dropdown-serial">{{ item.SerialNumber }}</text>
|
<text class="dropdown-name">{{ item.Name }}</text>
|
||||||
|
<text v-if="item.SerialNumber" class="dropdown-serial">{{ item.SerialNumber }}</text>
|
||||||
|
</view>
|
||||||
</view>
|
</view>
|
||||||
</view>
|
</view>
|
||||||
|
|
||||||
@@ -78,6 +86,56 @@
|
|||||||
</view>
|
</view>
|
||||||
</view>
|
</view>
|
||||||
|
|
||||||
|
<!-- 关联客户 -->
|
||||||
|
<view class="form-item">
|
||||||
|
<text class="form-label">关联客户</text>
|
||||||
|
|
||||||
|
<!-- 已选择客户 -->
|
||||||
|
<view v-if="selectedCustomers.length > 0" class="selected-customers">
|
||||||
|
<view
|
||||||
|
v-for="customer in selectedCustomers"
|
||||||
|
:key="customer.id"
|
||||||
|
class="selected-customer-tag"
|
||||||
|
>
|
||||||
|
<text class="customer-name">{{ (customer.last_name || '') + (customer.first_name ? ' ' + customer.first_name : '') }}</text>
|
||||||
|
<text class="remove-customer" @click="removeSelectedCustomer(customer.id)">×</text>
|
||||||
|
</view>
|
||||||
|
</view>
|
||||||
|
|
||||||
|
<!-- 搜索框 -->
|
||||||
|
<view class="search-box">
|
||||||
|
<input
|
||||||
|
v-model="customerSearchQuery"
|
||||||
|
class="form-input"
|
||||||
|
type="text"
|
||||||
|
placeholder="搜索客户姓名"
|
||||||
|
@input="onCustomerSearchInput"
|
||||||
|
@focus="onCustomerSearchFocus"
|
||||||
|
/>
|
||||||
|
|
||||||
|
<!-- 搜索结果下拉 -->
|
||||||
|
<view v-if="showCustomerDropdown && customerSearchResults.length > 0" class="dropdown">
|
||||||
|
<view
|
||||||
|
v-for="customer in customerSearchResults"
|
||||||
|
:key="customer.id"
|
||||||
|
class="dropdown-item"
|
||||||
|
@click="selectCustomer(customer)"
|
||||||
|
>
|
||||||
|
<text class="dropdown-name">{{ (customer.last_name || '') + (customer.first_name ? ' ' + customer.first_name : '') }}</text>
|
||||||
|
<text v-if="customer.primary_phone" class="dropdown-phone">{{ customer.primary_phone }}</text>
|
||||||
|
</view>
|
||||||
|
</view>
|
||||||
|
|
||||||
|
<view v-if="showCustomerDropdown && customerSearchLoading" class="dropdown">
|
||||||
|
<view class="dropdown-loading">搜索中...</view>
|
||||||
|
</view>
|
||||||
|
|
||||||
|
<view v-if="showCustomerDropdown && customerSearchResults.length === 0 && !customerSearchLoading && customerSearchQuery.trim()" class="dropdown">
|
||||||
|
<view class="dropdown-empty">未找到匹配的客户</view>
|
||||||
|
</view>
|
||||||
|
</view>
|
||||||
|
</view>
|
||||||
|
|
||||||
<!-- 图片上传 -->
|
<!-- 图片上传 -->
|
||||||
<view class="form-item">
|
<view class="form-item">
|
||||||
<text class="form-label">图片</text>
|
<text class="form-label">图片</text>
|
||||||
@@ -119,6 +177,7 @@ import { ref, reactive } from 'vue'
|
|||||||
import api from '@/api/index.js'
|
import api from '@/api/index.js'
|
||||||
import { workOrderApi } from '@/api/work_order.js'
|
import { workOrderApi } from '@/api/work_order.js'
|
||||||
import { warehouseApi } from '@/api/warehouse.js'
|
import { warehouseApi } from '@/api/warehouse.js'
|
||||||
|
import { customerApi } from '@/api/customer.js'
|
||||||
import { useConfigStore } from '@/stores/config.js'
|
import { useConfigStore } from '@/stores/config.js'
|
||||||
import { onLoad } from '@dcloudio/uni-app'
|
import { onLoad } from '@dcloudio/uni-app'
|
||||||
|
|
||||||
@@ -126,7 +185,7 @@ const configStore = useConfigStore()
|
|||||||
const goBack = () => uni.navigateBack()
|
const goBack = () => uni.navigateBack()
|
||||||
|
|
||||||
// 预填物品ID(从物品详情跳转时)
|
// 预填物品ID(从物品详情跳转时)
|
||||||
const presetItemId = ref(null)
|
const presetItemIds = ref([])
|
||||||
|
|
||||||
onLoad((options) => {
|
onLoad((options) => {
|
||||||
// 优先检查预填数据(从物品详情跳转时)
|
// 优先检查预填数据(从物品详情跳转时)
|
||||||
@@ -137,17 +196,26 @@ onLoad((options) => {
|
|||||||
form.title = prefill.title || ''
|
form.title = prefill.title || ''
|
||||||
form.description = prefill.description || ''
|
form.description = prefill.description || ''
|
||||||
if (prefill.itemId) {
|
if (prefill.itemId) {
|
||||||
presetItemId.value = prefill.itemId
|
presetItemIds.value = [prefill.itemId]
|
||||||
fetchPresetItem(prefill.itemId)
|
fetchPresetItem(prefill.itemId)
|
||||||
}
|
}
|
||||||
|
// 如果有预填客户信息,自动填充
|
||||||
|
if (prefill.customers && prefill.customers.length > 0) {
|
||||||
|
selectedCustomers.value = prefill.customers.map(c => ({
|
||||||
|
id: c.id,
|
||||||
|
first_name: c.first_name || '',
|
||||||
|
last_name: c.last_name || '',
|
||||||
|
primary_phone: c.primary_phone || ''
|
||||||
|
}))
|
||||||
|
}
|
||||||
uni.removeStorageSync('prefill_work_order')
|
uni.removeStorageSync('prefill_work_order')
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
console.error('读取预填数据失败', e)
|
console.error('读取预填数据失败', e)
|
||||||
}
|
}
|
||||||
} else if (options && options.item_id) {
|
} else if (options && options.item_id) {
|
||||||
// 兼容旧方式:直接传 item_id 参数
|
// 兼容旧方式:直接传 item_id 参数
|
||||||
presetItemId.value = parseInt(options.item_id)
|
presetItemIds.value = [parseInt(options.item_id)]
|
||||||
fetchPresetItem(presetItemId.value)
|
fetchPresetItem(parseInt(options.item_id))
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
|
|
||||||
@@ -155,8 +223,12 @@ async function fetchPresetItem(itemId) {
|
|||||||
try {
|
try {
|
||||||
const res = await warehouseApi.getItem(itemId)
|
const res = await warehouseApi.getItem(itemId)
|
||||||
if (res.errCode === 0 && res.data && res.data.item) {
|
if (res.errCode === 0 && res.data && res.data.item) {
|
||||||
selectedItem.value = res.data.item
|
const item = res.data.item
|
||||||
linkedItemId.value = itemId
|
// 检查是否已选中
|
||||||
|
if (!selectedItems.value.find(i => i.ID === item.ID)) {
|
||||||
|
selectedItems.value.push(item)
|
||||||
|
linkedItemIds.value.push(item.ID)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
console.error('获取物品信息失败', e)
|
console.error('获取物品信息失败', e)
|
||||||
@@ -170,14 +242,22 @@ const form = reactive({
|
|||||||
})
|
})
|
||||||
|
|
||||||
// 关联物品
|
// 关联物品
|
||||||
const selectedItem = ref(null)
|
const selectedItems = ref([])
|
||||||
const linkedItemId = ref(null)
|
const linkedItemIds = ref([])
|
||||||
const searchQuery = ref('')
|
const searchQuery = ref('')
|
||||||
const searchResults = ref([])
|
const searchResults = ref([])
|
||||||
const showDropdown = ref(false)
|
const showDropdown = ref(false)
|
||||||
const searchLoading = ref(false)
|
const searchLoading = ref(false)
|
||||||
let searchTimer = null
|
let searchTimer = null
|
||||||
|
|
||||||
|
// 关联客户
|
||||||
|
const selectedCustomers = ref([])
|
||||||
|
const customerSearchQuery = ref('')
|
||||||
|
const customerSearchResults = ref([])
|
||||||
|
const showCustomerDropdown = ref(false)
|
||||||
|
const customerSearchLoading = ref(false)
|
||||||
|
let customerSearchTimer = null
|
||||||
|
|
||||||
// 图片
|
// 图片
|
||||||
const photos = ref([])
|
const photos = ref([])
|
||||||
|
|
||||||
@@ -225,16 +305,75 @@ async function doSearch() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
function selectItem(item) {
|
function selectItem(item) {
|
||||||
selectedItem.value = item
|
// 检查是否已选中
|
||||||
linkedItemId.value = item.ID
|
if (!selectedItems.value.find(i => i.ID === item.ID)) {
|
||||||
|
selectedItems.value.push(item)
|
||||||
|
linkedItemIds.value.push(item.ID)
|
||||||
|
}
|
||||||
searchQuery.value = ''
|
searchQuery.value = ''
|
||||||
searchResults.value = []
|
searchResults.value = []
|
||||||
showDropdown.value = false
|
showDropdown.value = false
|
||||||
}
|
}
|
||||||
|
|
||||||
function clearSelectedItem() {
|
function removeSelectedItem(itemId) {
|
||||||
selectedItem.value = null
|
selectedItems.value = selectedItems.value.filter(i => i.ID !== itemId)
|
||||||
linkedItemId.value = null
|
linkedItemIds.value = linkedItemIds.value.filter(id => id !== itemId)
|
||||||
|
}
|
||||||
|
|
||||||
|
function onCustomerSearchInput() {
|
||||||
|
clearTimeout(customerSearchTimer)
|
||||||
|
customerSearchTimer = setTimeout(() => {
|
||||||
|
doCustomerSearch()
|
||||||
|
}, 300)
|
||||||
|
}
|
||||||
|
|
||||||
|
function onCustomerSearchFocus() {
|
||||||
|
if (customerSearchQuery.value.trim()) {
|
||||||
|
showCustomerDropdown.value = true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
async function doCustomerSearch() {
|
||||||
|
if (!customerSearchQuery.value.trim()) {
|
||||||
|
customerSearchResults.value = []
|
||||||
|
showCustomerDropdown.value = false
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
customerSearchLoading.value = true
|
||||||
|
showCustomerDropdown.value = true
|
||||||
|
|
||||||
|
try {
|
||||||
|
const res = await customerApi.list({
|
||||||
|
search: customerSearchQuery.value.trim(),
|
||||||
|
page: 1,
|
||||||
|
page_size: 10
|
||||||
|
})
|
||||||
|
if (res.errCode === 0 && res.data) {
|
||||||
|
customerSearchResults.value = (res.data.customers || []).slice(0, 10)
|
||||||
|
} else {
|
||||||
|
customerSearchResults.value = []
|
||||||
|
}
|
||||||
|
} catch (e) {
|
||||||
|
console.error('搜索客户失败', e)
|
||||||
|
customerSearchResults.value = []
|
||||||
|
} finally {
|
||||||
|
customerSearchLoading.value = false
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
function selectCustomer(customer) {
|
||||||
|
// 检查是否已选中
|
||||||
|
if (!selectedCustomers.value.find(c => c.id === customer.id)) {
|
||||||
|
selectedCustomers.value.push(customer)
|
||||||
|
}
|
||||||
|
customerSearchQuery.value = ''
|
||||||
|
customerSearchResults.value = []
|
||||||
|
showCustomerDropdown.value = false
|
||||||
|
}
|
||||||
|
|
||||||
|
function removeSelectedCustomer(customerId) {
|
||||||
|
selectedCustomers.value = selectedCustomers.value.filter(c => c.id !== customerId)
|
||||||
}
|
}
|
||||||
|
|
||||||
function getPhotoUrl(hash) {
|
function getPhotoUrl(hash) {
|
||||||
@@ -299,11 +438,12 @@ async function submitForm() {
|
|||||||
const data = {
|
const data = {
|
||||||
title: form.title.trim(),
|
title: form.title.trim(),
|
||||||
description: form.description.trim(),
|
description: form.description.trim(),
|
||||||
photos: photos.value
|
photos: photos.value,
|
||||||
|
customer_ids: selectedCustomers.value.map(c => c.id)
|
||||||
}
|
}
|
||||||
|
|
||||||
if (linkedItemId.value) {
|
if (linkedItemIds.value.length > 0) {
|
||||||
data.item_id = linkedItemId.value
|
data.item_ids = linkedItemIds.value
|
||||||
}
|
}
|
||||||
|
|
||||||
const res = await workOrderApi.add(data)
|
const res = await workOrderApi.add(data)
|
||||||
@@ -408,37 +548,42 @@ async function submitForm() {
|
|||||||
box-sizing: border-box;
|
box-sizing: border-box;
|
||||||
}
|
}
|
||||||
|
|
||||||
.selected-item {
|
.selected-customers {
|
||||||
|
display: flex;
|
||||||
|
flex-wrap: wrap;
|
||||||
|
gap: 15rpx;
|
||||||
|
margin-bottom: 20rpx;
|
||||||
|
}
|
||||||
|
|
||||||
|
.selected-customer-tag {
|
||||||
display: flex;
|
display: flex;
|
||||||
align-items: center;
|
align-items: center;
|
||||||
justify-content: space-between;
|
gap: 10rpx;
|
||||||
padding: 20rpx;
|
padding: 15rpx 20rpx;
|
||||||
background-color: #e6f7ff;
|
background-color: #e6f7ff;
|
||||||
border: 1rpx solid #91d5ff;
|
border: 1rpx solid #91d5ff;
|
||||||
border-radius: 10rpx;
|
border-radius: 30rpx;
|
||||||
}
|
font-size: 26rpx;
|
||||||
|
|
||||||
.selected-item-info {
|
|
||||||
flex: 1;
|
|
||||||
}
|
|
||||||
|
|
||||||
.selected-item-name {
|
|
||||||
display: block;
|
|
||||||
font-size: 28rpx;
|
|
||||||
color: #1890ff;
|
color: #1890ff;
|
||||||
}
|
}
|
||||||
|
|
||||||
.selected-item-serial {
|
.customer-name {
|
||||||
|
display: block;
|
||||||
|
font-size: 28rpx;
|
||||||
|
color: #333;
|
||||||
|
}
|
||||||
|
|
||||||
|
.dropdown-phone {
|
||||||
display: block;
|
display: block;
|
||||||
font-size: 24rpx;
|
font-size: 24rpx;
|
||||||
color: #8c8c8c;
|
color: #999;
|
||||||
margin-top: 5rpx;
|
margin-top: 5rpx;
|
||||||
}
|
}
|
||||||
|
|
||||||
.clear-btn {
|
.remove-customer {
|
||||||
font-size: 24rpx;
|
font-size: 28rpx;
|
||||||
color: #ff4d4f;
|
color: #ff4d4f;
|
||||||
padding: 10rpx;
|
padding: 5rpx;
|
||||||
}
|
}
|
||||||
|
|
||||||
.search-box {
|
.search-box {
|
||||||
@@ -546,6 +691,58 @@ async function submitForm() {
|
|||||||
margin-top: 10rpx;
|
margin-top: 10rpx;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.selected-items {
|
||||||
|
display: flex;
|
||||||
|
flex-wrap: wrap;
|
||||||
|
gap: 15rpx;
|
||||||
|
margin-bottom: 20rpx;
|
||||||
|
}
|
||||||
|
|
||||||
|
.selected-item-tag {
|
||||||
|
display: flex;
|
||||||
|
align-items: flex-start;
|
||||||
|
gap: 10rpx;
|
||||||
|
padding: 15rpx 20rpx;
|
||||||
|
background-color: #e6f7ff;
|
||||||
|
border: 1rpx solid #91d5ff;
|
||||||
|
border-radius: 10rpx;
|
||||||
|
font-size: 26rpx;
|
||||||
|
color: #1890ff;
|
||||||
|
max-width: 100%;
|
||||||
|
}
|
||||||
|
|
||||||
|
.selected-item-tag-info {
|
||||||
|
flex: 1;
|
||||||
|
overflow: hidden;
|
||||||
|
}
|
||||||
|
|
||||||
|
.selected-item-tag-name {
|
||||||
|
display: block;
|
||||||
|
font-size: 26rpx;
|
||||||
|
color: #1890ff;
|
||||||
|
word-break: break-all;
|
||||||
|
}
|
||||||
|
|
||||||
|
.selected-item-tag-serial {
|
||||||
|
display: block;
|
||||||
|
font-size: 22rpx;
|
||||||
|
color: #8c8c8c;
|
||||||
|
margin-top: 5rpx;
|
||||||
|
word-break: break-all;
|
||||||
|
}
|
||||||
|
|
||||||
|
.remove-item {
|
||||||
|
font-size: 28rpx;
|
||||||
|
color: #ff4d4f;
|
||||||
|
padding: 5rpx;
|
||||||
|
flex-shrink: 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
.dropdown-item-info {
|
||||||
|
display: flex;
|
||||||
|
flex-direction: column;
|
||||||
|
}
|
||||||
|
|
||||||
.submit-bar {
|
.submit-bar {
|
||||||
margin-top: 40rpx;
|
margin-top: 40rpx;
|
||||||
padding: 0 20rpx;
|
padding: 0 20rpx;
|
||||||
|
|||||||
@@ -41,6 +41,111 @@
|
|||||||
/>
|
/>
|
||||||
</view>
|
</view>
|
||||||
|
|
||||||
|
<!-- 关联物品 -->
|
||||||
|
<view class="form-item">
|
||||||
|
<text class="form-label">关联物品</text>
|
||||||
|
|
||||||
|
<!-- 已选择物品 -->
|
||||||
|
<view v-if="selectedItems.length > 0" class="selected-items">
|
||||||
|
<view
|
||||||
|
v-for="item in selectedItems"
|
||||||
|
:key="item.ID"
|
||||||
|
class="selected-item-tag"
|
||||||
|
>
|
||||||
|
<view class="selected-item-tag-info">
|
||||||
|
<text class="selected-item-tag-name">{{ item.Name }}</text>
|
||||||
|
<text v-if="item.SerialNumber" class="selected-item-tag-serial">{{ item.SerialNumber }}</text>
|
||||||
|
</view>
|
||||||
|
<text class="remove-item" @click="removeSelectedItem(item.ID)">×</text>
|
||||||
|
</view>
|
||||||
|
</view>
|
||||||
|
|
||||||
|
<!-- 搜索框 -->
|
||||||
|
<view class="search-box">
|
||||||
|
<input
|
||||||
|
v-model="searchQuery"
|
||||||
|
class="form-input"
|
||||||
|
type="text"
|
||||||
|
placeholder="搜索物品名称或编号"
|
||||||
|
@input="onSearchInput"
|
||||||
|
@focus="onSearchFocus"
|
||||||
|
/>
|
||||||
|
|
||||||
|
<!-- 搜索结果下拉 -->
|
||||||
|
<view v-if="showDropdown && searchResults.length > 0" class="dropdown">
|
||||||
|
<view
|
||||||
|
v-for="item in searchResults"
|
||||||
|
:key="item.ID"
|
||||||
|
class="dropdown-item"
|
||||||
|
@click="selectItem(item)"
|
||||||
|
>
|
||||||
|
<view class="dropdown-item-info">
|
||||||
|
<text class="dropdown-name">{{ item.Name }}</text>
|
||||||
|
<text v-if="item.SerialNumber" class="dropdown-serial">{{ item.SerialNumber }}</text>
|
||||||
|
</view>
|
||||||
|
</view>
|
||||||
|
</view>
|
||||||
|
|
||||||
|
<view v-if="showDropdown && searchLoading" class="dropdown">
|
||||||
|
<view class="dropdown-loading">搜索中...</view>
|
||||||
|
</view>
|
||||||
|
|
||||||
|
<view v-if="showDropdown && searchResults.length === 0 && !searchLoading && searchQuery.trim()" class="dropdown">
|
||||||
|
<view class="dropdown-empty">未找到匹配的物品</view>
|
||||||
|
</view>
|
||||||
|
</view>
|
||||||
|
</view>
|
||||||
|
|
||||||
|
<!-- 关联客户 -->
|
||||||
|
<view class="form-item">
|
||||||
|
<text class="form-label">关联客户</text>
|
||||||
|
|
||||||
|
<!-- 已选择客户 -->
|
||||||
|
<view v-if="selectedCustomers.length > 0" class="selected-customers">
|
||||||
|
<view
|
||||||
|
v-for="customer in selectedCustomers"
|
||||||
|
:key="customer.id"
|
||||||
|
class="selected-customer-tag"
|
||||||
|
>
|
||||||
|
<text class="customer-name">{{ (customer.last_name || '') + (customer.first_name ? ' ' + customer.first_name : '') }}</text>
|
||||||
|
<text class="remove-customer" @click="removeSelectedCustomer(customer.id)">×</text>
|
||||||
|
</view>
|
||||||
|
</view>
|
||||||
|
|
||||||
|
<!-- 搜索框 -->
|
||||||
|
<view class="search-box">
|
||||||
|
<input
|
||||||
|
v-model="customerSearchQuery"
|
||||||
|
class="form-input"
|
||||||
|
type="text"
|
||||||
|
placeholder="搜索客户姓名"
|
||||||
|
@input="onCustomerSearchInput"
|
||||||
|
@focus="onCustomerSearchFocus"
|
||||||
|
/>
|
||||||
|
|
||||||
|
<!-- 搜索结果下拉 -->
|
||||||
|
<view v-if="showCustomerDropdown && customerSearchResults.length > 0" class="dropdown">
|
||||||
|
<view
|
||||||
|
v-for="customer in customerSearchResults"
|
||||||
|
:key="customer.id"
|
||||||
|
class="dropdown-item"
|
||||||
|
@click="selectCustomer(customer)"
|
||||||
|
>
|
||||||
|
<text class="dropdown-name">{{ (customer.last_name || '') + (customer.first_name ? ' ' + customer.first_name : '') }}</text>
|
||||||
|
<text v-if="customer.primary_phone" class="dropdown-phone">{{ customer.primary_phone }}</text>
|
||||||
|
</view>
|
||||||
|
</view>
|
||||||
|
|
||||||
|
<view v-if="showCustomerDropdown && customerSearchLoading" class="dropdown">
|
||||||
|
<view class="dropdown-loading">搜索中...</view>
|
||||||
|
</view>
|
||||||
|
|
||||||
|
<view v-if="showCustomerDropdown && customerSearchResults.length === 0 && !customerSearchLoading && customerSearchQuery.trim()" class="dropdown">
|
||||||
|
<view class="dropdown-empty">未找到匹配的客户</view>
|
||||||
|
</view>
|
||||||
|
</view>
|
||||||
|
</view>
|
||||||
|
|
||||||
<!-- 图片上传 -->
|
<!-- 图片上传 -->
|
||||||
<view class="form-item">
|
<view class="form-item">
|
||||||
<text class="form-label">图片</text>
|
<text class="form-label">图片</text>
|
||||||
@@ -92,6 +197,8 @@
|
|||||||
<script setup>
|
<script setup>
|
||||||
import { ref, reactive, onMounted } from 'vue'
|
import { ref, reactive, onMounted } from 'vue'
|
||||||
import { workOrderApi } from '@/api/work_order.js'
|
import { workOrderApi } from '@/api/work_order.js'
|
||||||
|
import { warehouseApi } from '@/api/warehouse.js'
|
||||||
|
import { customerApi } from '@/api/customer.js'
|
||||||
import api from '@/api/index.js'
|
import api from '@/api/index.js'
|
||||||
import { useConfigStore } from '@/stores/config.js'
|
import { useConfigStore } from '@/stores/config.js'
|
||||||
|
|
||||||
@@ -107,6 +214,23 @@ const pageError = ref('')
|
|||||||
const submitting = ref(false)
|
const submitting = ref(false)
|
||||||
const showDeleteConfirm = ref(false)
|
const showDeleteConfirm = ref(false)
|
||||||
|
|
||||||
|
// 关联物品
|
||||||
|
const selectedItems = ref([])
|
||||||
|
const linkedItemIds = ref([])
|
||||||
|
const searchQuery = ref('')
|
||||||
|
const searchResults = ref([])
|
||||||
|
const showDropdown = ref(false)
|
||||||
|
const searchLoading = ref(false)
|
||||||
|
let searchTimer = null
|
||||||
|
|
||||||
|
// 关联客户
|
||||||
|
const selectedCustomers = ref([])
|
||||||
|
const customerSearchQuery = ref('')
|
||||||
|
const customerSearchResults = ref([])
|
||||||
|
const showCustomerDropdown = ref(false)
|
||||||
|
const customerSearchLoading = ref(false)
|
||||||
|
let customerSearchTimer = null
|
||||||
|
|
||||||
// 表单数据
|
// 表单数据
|
||||||
const form = reactive({
|
const form = reactive({
|
||||||
title: '',
|
title: '',
|
||||||
@@ -128,6 +252,120 @@ function previewPhoto(index) {
|
|||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// 物品搜索
|
||||||
|
function onSearchInput() {
|
||||||
|
clearTimeout(searchTimer)
|
||||||
|
searchTimer = setTimeout(() => {
|
||||||
|
doSearch()
|
||||||
|
}, 300)
|
||||||
|
}
|
||||||
|
|
||||||
|
function onSearchFocus() {
|
||||||
|
if (searchQuery.value.trim()) {
|
||||||
|
showDropdown.value = true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
async function doSearch() {
|
||||||
|
if (!searchQuery.value.trim()) {
|
||||||
|
searchResults.value = []
|
||||||
|
showDropdown.value = false
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
searchLoading.value = true
|
||||||
|
showDropdown.value = true
|
||||||
|
|
||||||
|
try {
|
||||||
|
const res = await warehouseApi.listItem({
|
||||||
|
search: searchQuery.value.trim()
|
||||||
|
})
|
||||||
|
if (res.errCode === 0 && res.data) {
|
||||||
|
searchResults.value = (res.data.items || []).slice(0, 10)
|
||||||
|
} else {
|
||||||
|
searchResults.value = []
|
||||||
|
}
|
||||||
|
} catch (e) {
|
||||||
|
console.error('搜索物品失败', e)
|
||||||
|
searchResults.value = []
|
||||||
|
} finally {
|
||||||
|
searchLoading.value = false
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
function selectItem(item) {
|
||||||
|
// 检查是否已选中
|
||||||
|
if (!selectedItems.value.find(i => i.ID === item.ID)) {
|
||||||
|
selectedItems.value.push(item)
|
||||||
|
linkedItemIds.value.push(item.ID)
|
||||||
|
}
|
||||||
|
searchQuery.value = ''
|
||||||
|
searchResults.value = []
|
||||||
|
showDropdown.value = false
|
||||||
|
}
|
||||||
|
|
||||||
|
function removeSelectedItem(itemId) {
|
||||||
|
selectedItems.value = selectedItems.value.filter(i => i.ID !== itemId)
|
||||||
|
linkedItemIds.value = linkedItemIds.value.filter(id => id !== itemId)
|
||||||
|
}
|
||||||
|
|
||||||
|
// 客户搜索
|
||||||
|
function onCustomerSearchInput() {
|
||||||
|
clearTimeout(customerSearchTimer)
|
||||||
|
customerSearchTimer = setTimeout(() => {
|
||||||
|
doCustomerSearch()
|
||||||
|
}, 300)
|
||||||
|
}
|
||||||
|
|
||||||
|
function onCustomerSearchFocus() {
|
||||||
|
if (customerSearchQuery.value.trim()) {
|
||||||
|
showCustomerDropdown.value = true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
async function doCustomerSearch() {
|
||||||
|
if (!customerSearchQuery.value.trim()) {
|
||||||
|
customerSearchResults.value = []
|
||||||
|
showCustomerDropdown.value = false
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
customerSearchLoading.value = true
|
||||||
|
showCustomerDropdown.value = true
|
||||||
|
|
||||||
|
try {
|
||||||
|
const res = await customerApi.list({
|
||||||
|
search: customerSearchQuery.value.trim(),
|
||||||
|
page: 1,
|
||||||
|
page_size: 10
|
||||||
|
})
|
||||||
|
if (res.errCode === 0 && res.data) {
|
||||||
|
customerSearchResults.value = (res.data.customers || []).slice(0, 10)
|
||||||
|
} else {
|
||||||
|
customerSearchResults.value = []
|
||||||
|
}
|
||||||
|
} catch (e) {
|
||||||
|
console.error('搜索客户失败', e)
|
||||||
|
customerSearchResults.value = []
|
||||||
|
} finally {
|
||||||
|
customerSearchLoading.value = false
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
function selectCustomer(customer) {
|
||||||
|
// 检查是否已选中
|
||||||
|
if (!selectedCustomers.value.find(c => c.id === customer.id)) {
|
||||||
|
selectedCustomers.value.push(customer)
|
||||||
|
}
|
||||||
|
customerSearchQuery.value = ''
|
||||||
|
customerSearchResults.value = []
|
||||||
|
showCustomerDropdown.value = false
|
||||||
|
}
|
||||||
|
|
||||||
|
function removeSelectedCustomer(customerId) {
|
||||||
|
selectedCustomers.value = selectedCustomers.value.filter(c => c.id !== customerId)
|
||||||
|
}
|
||||||
|
|
||||||
// 加载工单数据
|
// 加载工单数据
|
||||||
async function fetchOrder() {
|
async function fetchOrder() {
|
||||||
pageLoading.value = true
|
pageLoading.value = true
|
||||||
@@ -138,6 +376,17 @@ async function fetchOrder() {
|
|||||||
form.title = order.Title || ''
|
form.title = order.Title || ''
|
||||||
form.description = order.Description || ''
|
form.description = order.Description || ''
|
||||||
photos.value = res.data.photos || []
|
photos.value = res.data.photos || []
|
||||||
|
|
||||||
|
// 加载已关联的物品
|
||||||
|
if (res.data.linkedItems && res.data.linkedItems.length > 0) {
|
||||||
|
selectedItems.value = res.data.linkedItems
|
||||||
|
linkedItemIds.value = res.data.linkedItems.map(item => item.ID)
|
||||||
|
}
|
||||||
|
|
||||||
|
// 加载已关联的客户
|
||||||
|
if (res.data.linkedCustomers && res.data.linkedCustomers.length > 0) {
|
||||||
|
selectedCustomers.value = res.data.linkedCustomers
|
||||||
|
}
|
||||||
} else {
|
} else {
|
||||||
pageError.value = '工单不存在'
|
pageError.value = '工单不存在'
|
||||||
}
|
}
|
||||||
@@ -207,6 +456,16 @@ async function submitForm() {
|
|||||||
photos: photos.value.map(p => p.Sha256)
|
photos: photos.value.map(p => p.Sha256)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// 添加关联物品
|
||||||
|
if (linkedItemIds.value.length > 0) {
|
||||||
|
data.item_ids = linkedItemIds.value
|
||||||
|
}
|
||||||
|
|
||||||
|
// 添加关联客户
|
||||||
|
if (selectedCustomers.value.length > 0) {
|
||||||
|
data.customer_ids = selectedCustomers.value.map(c => c.id)
|
||||||
|
}
|
||||||
|
|
||||||
const res = await workOrderApi.update(data)
|
const res = await workOrderApi.update(data)
|
||||||
|
|
||||||
if (res.errCode === 0) {
|
if (res.errCode === 0) {
|
||||||
@@ -488,4 +747,142 @@ onMounted(() => {
|
|||||||
font-size: 32rpx;
|
font-size: 32rpx;
|
||||||
color: #fff;
|
color: #fff;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.selected-items {
|
||||||
|
display: flex;
|
||||||
|
flex-wrap: wrap;
|
||||||
|
gap: 15rpx;
|
||||||
|
margin-bottom: 20rpx;
|
||||||
|
}
|
||||||
|
|
||||||
|
.selected-item-tag {
|
||||||
|
display: flex;
|
||||||
|
align-items: flex-start;
|
||||||
|
gap: 10rpx;
|
||||||
|
padding: 15rpx 20rpx;
|
||||||
|
background-color: #e6f7ff;
|
||||||
|
border:1rpx solid #91d5ff;
|
||||||
|
border-radius: 10rpx;
|
||||||
|
font-size: 26rpx;
|
||||||
|
color: #1890ff;
|
||||||
|
max-width: 100%;
|
||||||
|
}
|
||||||
|
|
||||||
|
.selected-item-tag-info {
|
||||||
|
flex:1;
|
||||||
|
overflow: hidden;
|
||||||
|
}
|
||||||
|
|
||||||
|
.selected-item-tag-name {
|
||||||
|
display: block;
|
||||||
|
font-size: 26rpx;
|
||||||
|
color: #1890ff;
|
||||||
|
word-break: break-all;
|
||||||
|
}
|
||||||
|
|
||||||
|
.selected-item-tag-serial {
|
||||||
|
display: block;
|
||||||
|
font-size: 22rpx;
|
||||||
|
color: #8c8c8c;
|
||||||
|
margin-top: 5rpx;
|
||||||
|
word-break: break-all;
|
||||||
|
}
|
||||||
|
|
||||||
|
.remove-item {
|
||||||
|
font-size: 28rpx;
|
||||||
|
color: #ff4d4f;
|
||||||
|
padding: 5rpx;
|
||||||
|
flex-shrink: 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
.selected-customers {
|
||||||
|
display: flex;
|
||||||
|
flex-wrap: wrap;
|
||||||
|
gap: 15rpx;
|
||||||
|
margin-bottom: 20rpx;
|
||||||
|
}
|
||||||
|
|
||||||
|
.selected-customer-tag {
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
gap: 10rpx;
|
||||||
|
padding: 15rpx 20rpx;
|
||||||
|
background-color: #e6f7ff;
|
||||||
|
border:1rpx solid #91d5ff;
|
||||||
|
border-radius: 30rpx;
|
||||||
|
font-size: 26rpx;
|
||||||
|
color: #1890ff;
|
||||||
|
}
|
||||||
|
|
||||||
|
.customer-name {
|
||||||
|
display: block;
|
||||||
|
font-size: 28rpx;
|
||||||
|
color: #333;
|
||||||
|
}
|
||||||
|
|
||||||
|
.dropdown-phone {
|
||||||
|
display: block;
|
||||||
|
font-size: 24rpx;
|
||||||
|
color: #999;
|
||||||
|
margin-top: 5rpx;
|
||||||
|
}
|
||||||
|
|
||||||
|
.remove-customer {
|
||||||
|
font-size: 28rpx;
|
||||||
|
color: #ff4d4f;
|
||||||
|
padding: 5rpx;
|
||||||
|
}
|
||||||
|
|
||||||
|
.search-box {
|
||||||
|
position: relative;
|
||||||
|
}
|
||||||
|
|
||||||
|
.dropdown {
|
||||||
|
position: absolute;
|
||||||
|
top: 90rpx;
|
||||||
|
left: 0;
|
||||||
|
right: 0;
|
||||||
|
background-color: #fff;
|
||||||
|
border:1rpx solid #e5e5e5;
|
||||||
|
border-radius: 10rpx;
|
||||||
|
max-height: 400rpx;
|
||||||
|
overflow-y: auto;
|
||||||
|
z-index: 100;
|
||||||
|
box-shadow: 0 4rpx 12rpx rgba(0, 0, 0, 0.1);
|
||||||
|
}
|
||||||
|
|
||||||
|
.dropdown-item {
|
||||||
|
padding: 20rpx;
|
||||||
|
border-bottom:1rpx solid #f0f0f0;
|
||||||
|
}
|
||||||
|
|
||||||
|
.dropdown-item:last-child {
|
||||||
|
border-bottom: none;
|
||||||
|
}
|
||||||
|
|
||||||
|
.dropdown-item-info {
|
||||||
|
display: flex;
|
||||||
|
flex-direction: column;
|
||||||
|
}
|
||||||
|
|
||||||
|
.dropdown-name {
|
||||||
|
display: block;
|
||||||
|
font-size: 28rpx;
|
||||||
|
color: #333;
|
||||||
|
}
|
||||||
|
|
||||||
|
.dropdown-serial {
|
||||||
|
display: block;
|
||||||
|
font-size: 24rpx;
|
||||||
|
color: #999;
|
||||||
|
margin-top: 5rpx;
|
||||||
|
}
|
||||||
|
|
||||||
|
.dropdown-loading,
|
||||||
|
.dropdown-empty {
|
||||||
|
padding: 30rpx;
|
||||||
|
text-align: center;
|
||||||
|
font-size: 26rpx;
|
||||||
|
color: #999;
|
||||||
|
}
|
||||||
</style>
|
</style>
|
||||||
|
|||||||
@@ -58,6 +58,21 @@
|
|||||||
</view>
|
</view>
|
||||||
</view>
|
</view>
|
||||||
|
|
||||||
|
<!-- 关联客户 -->
|
||||||
|
<view v-if="linkedCustomers.length > 0" class="info-item">
|
||||||
|
<text class="info-label">关联客户</text>
|
||||||
|
<view class="linked-customers">
|
||||||
|
<view
|
||||||
|
v-for="customer in linkedCustomers"
|
||||||
|
:key="customer.id"
|
||||||
|
class="linked-customer"
|
||||||
|
>
|
||||||
|
<text class="linked-customer-name">{{ (customer.last_name || '') + (customer.first_name ? ' ' + customer.first_name : '') }}</text>
|
||||||
|
<text v-if="customer.primary_phone" class="linked-customer-phone">{{ customer.primary_phone }}</text>
|
||||||
|
</view>
|
||||||
|
</view>
|
||||||
|
</view>
|
||||||
|
|
||||||
<!-- 关联采购订单汇总(去重) -->
|
<!-- 关联采购订单汇总(去重) -->
|
||||||
<view v-if="allPurchaseOrders.length > 0" class="info-item">
|
<view v-if="allPurchaseOrders.length > 0" class="info-item">
|
||||||
<text class="info-label">关联采购订单</text>
|
<text class="info-label">关联采购订单</text>
|
||||||
@@ -283,6 +298,7 @@ const order = ref({})
|
|||||||
const photos = ref([])
|
const photos = ref([])
|
||||||
const commits = ref([])
|
const commits = ref([])
|
||||||
const linkedItems = ref([])
|
const linkedItems = ref([])
|
||||||
|
const linkedCustomers = ref([])
|
||||||
const canCommit = ref(false)
|
const canCommit = ref(false)
|
||||||
const canModify = ref(false)
|
const canModify = ref(false)
|
||||||
|
|
||||||
@@ -341,6 +357,7 @@ async function fetchOrderDetail() {
|
|||||||
photos.value = res.data.photos || []
|
photos.value = res.data.photos || []
|
||||||
commits.value = res.data.commits || []
|
commits.value = res.data.commits || []
|
||||||
linkedItems.value = res.data.linkedItems || []
|
linkedItems.value = res.data.linkedItems || []
|
||||||
|
linkedCustomers.value = res.data.linkedCustomers || []
|
||||||
canCommit.value = res.data.canCommit || false
|
canCommit.value = res.data.canCommit || false
|
||||||
canModify.value = res.data.canModify || false
|
canModify.value = res.data.canModify || false
|
||||||
} else {
|
} else {
|
||||||
@@ -800,6 +817,33 @@ async function onRefresh() {
|
|||||||
color: #8c8c8c;
|
color: #8c8c8c;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.linked-customers {
|
||||||
|
display: flex;
|
||||||
|
flex-wrap: wrap;
|
||||||
|
gap: 16rpx;
|
||||||
|
}
|
||||||
|
|
||||||
|
.linked-customer {
|
||||||
|
display: inline-flex;
|
||||||
|
align-items: center;
|
||||||
|
gap: 8rpx;
|
||||||
|
padding: 10rpx 20rpx;
|
||||||
|
background-color: #e6f7ff;
|
||||||
|
border: 1rpx solid #91d5ff;
|
||||||
|
border-radius: 30rpx;
|
||||||
|
}
|
||||||
|
|
||||||
|
.linked-customer-name {
|
||||||
|
font-size: 24rpx;
|
||||||
|
color: #1890ff;
|
||||||
|
}
|
||||||
|
|
||||||
|
.linked-customer-phone {
|
||||||
|
font-size: 22rpx;
|
||||||
|
color: #8c8c8c;
|
||||||
|
margin-left: 8rpx;
|
||||||
|
}
|
||||||
|
|
||||||
/* 关联采购订单 */
|
/* 关联采购订单 */
|
||||||
.linked-pos {
|
.linked-pos {
|
||||||
display: flex;
|
display: flex;
|
||||||
|
|||||||
Reference in New Issue
Block a user