@@ -36,16 +36,22 @@
|
||||
<text class="form-label">关联物品</text>
|
||||
|
||||
<!-- 已选择物品 -->
|
||||
<view v-if="selectedItem" class="selected-item">
|
||||
<view class="selected-item-info">
|
||||
<text class="selected-item-name">{{ selectedItem.Name }}</text>
|
||||
<text v-if="selectedItem.SerialNumber" class="selected-item-serial">{{ selectedItem.SerialNumber }}</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>
|
||||
<text class="clear-btn" @click="clearSelectedItem">清除</text>
|
||||
</view>
|
||||
|
||||
<!-- 搜索框 -->
|
||||
<view v-else class="search-box">
|
||||
<view class="search-box">
|
||||
<input
|
||||
v-model="searchQuery"
|
||||
class="form-input"
|
||||
@@ -63,8 +69,10 @@
|
||||
class="dropdown-item"
|
||||
@click="selectItem(item)"
|
||||
>
|
||||
<text class="dropdown-name">{{ item.Name }}</text>
|
||||
<text v-if="item.SerialNumber" class="dropdown-serial">{{ item.SerialNumber }}</text>
|
||||
<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>
|
||||
|
||||
@@ -78,6 +86,56 @@
|
||||
</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">
|
||||
<text class="form-label">图片</text>
|
||||
@@ -119,6 +177,7 @@ import { ref, reactive } from 'vue'
|
||||
import api from '@/api/index.js'
|
||||
import { workOrderApi } from '@/api/work_order.js'
|
||||
import { warehouseApi } from '@/api/warehouse.js'
|
||||
import { customerApi } from '@/api/customer.js'
|
||||
import { useConfigStore } from '@/stores/config.js'
|
||||
import { onLoad } from '@dcloudio/uni-app'
|
||||
|
||||
@@ -126,7 +185,7 @@ const configStore = useConfigStore()
|
||||
const goBack = () => uni.navigateBack()
|
||||
|
||||
// 预填物品ID(从物品详情跳转时)
|
||||
const presetItemId = ref(null)
|
||||
const presetItemIds = ref([])
|
||||
|
||||
onLoad((options) => {
|
||||
// 优先检查预填数据(从物品详情跳转时)
|
||||
@@ -137,17 +196,26 @@ onLoad((options) => {
|
||||
form.title = prefill.title || ''
|
||||
form.description = prefill.description || ''
|
||||
if (prefill.itemId) {
|
||||
presetItemId.value = prefill.itemId
|
||||
presetItemIds.value = [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')
|
||||
} catch (e) {
|
||||
console.error('读取预填数据失败', e)
|
||||
}
|
||||
} else if (options && options.item_id) {
|
||||
// 兼容旧方式:直接传 item_id 参数
|
||||
presetItemId.value = parseInt(options.item_id)
|
||||
fetchPresetItem(presetItemId.value)
|
||||
presetItemIds.value = [parseInt(options.item_id)]
|
||||
fetchPresetItem(parseInt(options.item_id))
|
||||
}
|
||||
})
|
||||
|
||||
@@ -155,8 +223,12 @@ async function fetchPresetItem(itemId) {
|
||||
try {
|
||||
const res = await warehouseApi.getItem(itemId)
|
||||
if (res.errCode === 0 && res.data && res.data.item) {
|
||||
selectedItem.value = res.data.item
|
||||
linkedItemId.value = itemId
|
||||
const item = res.data.item
|
||||
// 检查是否已选中
|
||||
if (!selectedItems.value.find(i => i.ID === item.ID)) {
|
||||
selectedItems.value.push(item)
|
||||
linkedItemIds.value.push(item.ID)
|
||||
}
|
||||
}
|
||||
} catch (e) {
|
||||
console.error('获取物品信息失败', e)
|
||||
@@ -170,14 +242,22 @@ const form = reactive({
|
||||
})
|
||||
|
||||
// 关联物品
|
||||
const selectedItem = ref(null)
|
||||
const linkedItemId = ref(null)
|
||||
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 photos = ref([])
|
||||
|
||||
@@ -225,16 +305,75 @@ async function doSearch() {
|
||||
}
|
||||
|
||||
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 = ''
|
||||
searchResults.value = []
|
||||
showDropdown.value = false
|
||||
}
|
||||
|
||||
function clearSelectedItem() {
|
||||
selectedItem.value = null
|
||||
linkedItemId.value = null
|
||||
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)
|
||||
}
|
||||
|
||||
function getPhotoUrl(hash) {
|
||||
@@ -299,11 +438,12 @@ async function submitForm() {
|
||||
const data = {
|
||||
title: form.title.trim(),
|
||||
description: form.description.trim(),
|
||||
photos: photos.value
|
||||
photos: photos.value,
|
||||
customer_ids: selectedCustomers.value.map(c => c.id)
|
||||
}
|
||||
|
||||
if (linkedItemId.value) {
|
||||
data.item_id = linkedItemId.value
|
||||
if (linkedItemIds.value.length > 0) {
|
||||
data.item_ids = linkedItemIds.value
|
||||
}
|
||||
|
||||
const res = await workOrderApi.add(data)
|
||||
@@ -408,37 +548,42 @@ async function submitForm() {
|
||||
box-sizing: border-box;
|
||||
}
|
||||
|
||||
.selected-item {
|
||||
.selected-customers {
|
||||
display: flex;
|
||||
flex-wrap: wrap;
|
||||
gap: 15rpx;
|
||||
margin-bottom: 20rpx;
|
||||
}
|
||||
|
||||
.selected-customer-tag {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: space-between;
|
||||
padding: 20rpx;
|
||||
gap: 10rpx;
|
||||
padding: 15rpx 20rpx;
|
||||
background-color: #e6f7ff;
|
||||
border: 1rpx solid #91d5ff;
|
||||
border-radius: 10rpx;
|
||||
}
|
||||
|
||||
.selected-item-info {
|
||||
flex: 1;
|
||||
}
|
||||
|
||||
.selected-item-name {
|
||||
display: block;
|
||||
font-size: 28rpx;
|
||||
border-radius: 30rpx;
|
||||
font-size: 26rpx;
|
||||
color: #1890ff;
|
||||
}
|
||||
|
||||
.selected-item-serial {
|
||||
.customer-name {
|
||||
display: block;
|
||||
font-size: 28rpx;
|
||||
color: #333;
|
||||
}
|
||||
|
||||
.dropdown-phone {
|
||||
display: block;
|
||||
font-size: 24rpx;
|
||||
color: #8c8c8c;
|
||||
color: #999;
|
||||
margin-top: 5rpx;
|
||||
}
|
||||
|
||||
.clear-btn {
|
||||
font-size: 24rpx;
|
||||
.remove-customer {
|
||||
font-size: 28rpx;
|
||||
color: #ff4d4f;
|
||||
padding: 10rpx;
|
||||
padding: 5rpx;
|
||||
}
|
||||
|
||||
.search-box {
|
||||
@@ -546,6 +691,58 @@ async function submitForm() {
|
||||
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 {
|
||||
margin-top: 40rpx;
|
||||
padding: 0 20rpx;
|
||||
|
||||
Reference in New Issue
Block a user