Compare commits

3 Commits

Author SHA1 Message Date
dxc
b5b0677b01 feat: align service inbound material search with buy/semi
Co-authored-by: aider (openai/DeepSeek-V3.2-Thinking) <aider@aider.chat>
2026-02-10 15:16:03 +08:00
dxc
8d00e6783c feat: add provider autocomplete to service form
Co-authored-by: aider (openai/DeepSeek-V3.2-Thinking) <aider@aider.chat>
2026-02-10 15:10:55 +08:00
dxc
695c78090a refactor: remove localStorage usage for column visibility and history
Co-authored-by: aider (openai/DeepSeek-V3.2-Thinking) <aider@aider.chat>
2026-02-10 15:03:52 +08:00
3 changed files with 53 additions and 14 deletions

View File

@ -419,10 +419,7 @@ const allColumns = [
]
const defaultVisibleCols = ['material_name', 'sku', 'serial_number', 'qty_stock', 'status', 'quality_status', 'product_photo', 'sale_price', 'order_id']
const STORAGE_KEY = 'stock_product_visible_columns_v2'
const getSavedColumns = () => { try { const saved = localStorage.getItem(STORAGE_KEY); return saved ? JSON.parse(saved) : defaultVisibleCols } catch (e) { return defaultVisibleCols } }
const visibleColumnProps = ref(getSavedColumns())
watch(visibleColumnProps, (newVal) => { localStorage.setItem(STORAGE_KEY, JSON.stringify(newVal)) }, { deep: true })
const visibleColumnProps = ref(defaultVisibleCols)
const form = reactive({
id: undefined, base_id: undefined, material_name: '', spec_model: '', material_type: '', category: '', unit: '',

View File

@ -513,11 +513,8 @@ const stockColumns = [
]
const allColumns = [...baseColumns, ...stockColumns]
const STORAGE_KEY = 'stock_semi_visible_columns_v2'
const defaultColumns = ['material_name', 'spec_model', 'unit', 'inbound_date', 'sn_bn', 'status', 'quality_status', 'bom_code', 'work_order_code', 'qty_stock', 'qty_available', 'unit_total_cost', 'arrival_photo', 'quality_report_link']
const getSavedColumns = () => { try { const saved = localStorage.getItem(STORAGE_KEY); return saved ? JSON.parse(saved) : defaultColumns } catch (e) { return defaultColumns } }
const visibleColumnProps = ref(getSavedColumns())
watch(visibleColumnProps, (newVal) => { localStorage.setItem(STORAGE_KEY, JSON.stringify(newVal)) }, {deep: true})
const visibleColumnProps = ref(defaultColumns)
const form = reactive({
id: undefined, base_id: undefined as number | undefined, material_name: '', spec_model: '', category: '', unit: '', material_type: '',
@ -527,9 +524,6 @@ const form = reactive({
production_manager: '', production_time_range: [] as string[], arrival_photo: [] as string[], quality_report_link: [] as string[], detail_link: ''
})
// ------------------------------------
// 历史记录管理器
// ------------------------------------
// ------------------------------------
// Autocomplete & Search Logic (后端 API 驱动)
// ------------------------------------

View File

@ -161,9 +161,14 @@
/>
</el-form-item>
<el-form-item label="服务商" prop="provider_name">
<el-input
<el-autocomplete
v-model="form.provider_name"
placeholder="请输入服务商名称"
:fetch-suggestions="querySearchProvider"
placeholder="输入或选择服务商"
style="width: 100%"
clearable
:trigger-on-focus="true"
@select="handleProviderSelect"
/>
</el-form-item>
<el-form-item label="简介" prop="description">
@ -199,6 +204,8 @@ import {
updateService,
deleteService,
searchMaterialBase,
getProviderSuggestions,
getUserSuggestions,
type ServiceItem,
type ServiceQueryParams,
type ServiceCreateRequest,
@ -283,7 +290,8 @@ const handleSearchMaterial = async (query: string) => {
try {
const res = await searchMaterialBase(query)
if (res.code === 200) {
materialOptions.value = res.data
const apiResults = (res.data || []).map((i: any) => ({ ...i, isHistory: false }))
materialOptions.value = apiResults
} else {
materialOptions.value = []
}
@ -305,6 +313,30 @@ const onMaterialSelected = (val: number) => {
}
}
// 服务商建议
const fetchProviderSuggestions = async (query: string, cb: any) => {
if (!form.base_id) {
cb([])
return
}
try {
const res: any = await getProviderSuggestions({ base_id: form.base_id })
if (res.code === 200) {
const providers = res.data.map((name: string) => ({ value: name }))
const filtered = query ? providers.filter((item: any) => item.value.toLowerCase().includes(query.toLowerCase())) : providers
cb(filtered)
} else {
cb([])
}
} catch (e) {
cb([])
}
}
const querySearchProvider = (qs: string, cb: any) => fetchProviderSuggestions(qs, cb)
const handleProviderSelect = (item: any) => {
form.provider_name = item.value
}
// 弹窗相关
const dialogVisible = ref(false)
const dialogTitle = ref('')
@ -490,4 +522,20 @@ onMounted(() => {
font-weight: 600;
color: #409EFF;
}
/* Material search options matching buy/semi style */
.option-item {
display: flex;
justify-content: space-between;
width: 100%;
align-items: center;
}
.opt-name {
font-weight: bold;
}
.opt-spec {
color: #8492a6;
font-size: 13px;
margin-right: 10px;
}
</style>