|
@@ -30,25 +30,29 @@
|
|
|
</el-form-item>
|
|
</el-form-item>
|
|
|
|
|
|
|
|
<el-form-item :label="form.biz_type === 'product' ? '产品编号' : '工单编号'">
|
|
<el-form-item :label="form.biz_type === 'product' ? '产品编号' : '工单编号'">
|
|
|
- <el-select
|
|
|
|
|
|
|
+ <el-autocomplete
|
|
|
v-model="form.no"
|
|
v-model="form.no"
|
|
|
- filterable
|
|
|
|
|
- allow-create
|
|
|
|
|
- default-first-option
|
|
|
|
|
|
|
+ :fetch-suggestions="searchBiz"
|
|
|
|
|
+ :debounce="300"
|
|
|
|
|
+ :trigger-on-focus="false"
|
|
|
clearable
|
|
clearable
|
|
|
:disabled="lockBiz"
|
|
:disabled="lockBiz"
|
|
|
- :placeholder="form.biz_type === 'product' ? '选择已有产品,或直接输入编号' : '选择已有工单,或直接输入编号'"
|
|
|
|
|
|
|
+ :placeholder="form.biz_type === 'product' ? '输入编号或名称搜索,也可直接手填' : '输入工单号或名称搜索,也可直接手填'"
|
|
|
style="width:100%"
|
|
style="width:100%"
|
|
|
- @change="onNoChange"
|
|
|
|
|
|
|
+ value-key="value"
|
|
|
|
|
+ @select="onBizPick"
|
|
|
|
|
+ @input="onBizInput"
|
|
|
|
|
+ @clear="onBizClear"
|
|
|
>
|
|
>
|
|
|
- <el-option
|
|
|
|
|
- v-for="item in bizOptions"
|
|
|
|
|
- :key="item.id"
|
|
|
|
|
- :label="optionLabel(item)"
|
|
|
|
|
- :value="optionValue(item)"
|
|
|
|
|
- />
|
|
|
|
|
- </el-select>
|
|
|
|
|
- <p class="field-hint">{{ isExisting ? '已匹配到本厂记录,将带出保存工艺' : '未匹配记录,可直接填写信息并临时添加工艺后打印' }}</p>
|
|
|
|
|
|
|
+ <template #default="{ item }">
|
|
|
|
|
+ <div class="biz-suggest">
|
|
|
|
|
+ <span class="biz-suggest-no">{{ item.value }}</span>
|
|
|
|
|
+ <span class="biz-suggest-name">{{ item.subtitle }}</span>
|
|
|
|
|
+ </div>
|
|
|
|
|
+ </template>
|
|
|
|
|
+ </el-autocomplete>
|
|
|
|
|
+ <p v-if="bizSearching" class="field-hint">正在搜索…</p>
|
|
|
|
|
+ <p v-else class="field-hint">{{ isExisting ? '已匹配到本厂记录,将带出保存工艺' : '输入编号或名称搜索后点选;未匹配记录可手填并临时添加工艺' }}</p>
|
|
|
</el-form-item>
|
|
</el-form-item>
|
|
|
|
|
|
|
|
<el-form-item label="名称">
|
|
<el-form-item label="名称">
|
|
@@ -176,8 +180,8 @@ const syncing = ref(false)
|
|
|
const emit = defineEmits(['update:modelValue', 'done'])
|
|
const emit = defineEmits(['update:modelValue', 'done'])
|
|
|
|
|
|
|
|
const templates = ref([])
|
|
const templates = ref([])
|
|
|
-const workorders = ref([])
|
|
|
|
|
-const products = ref([])
|
|
|
|
|
|
|
+const bizSearching = ref(false)
|
|
|
|
|
+const boundBizNo = ref('')
|
|
|
const preparing = ref(false)
|
|
const preparing = ref(false)
|
|
|
const saving = ref(false)
|
|
const saving = ref(false)
|
|
|
const preview = ref(null)
|
|
const preview = ref(null)
|
|
@@ -200,7 +204,6 @@ const form = reactive({
|
|
|
const lockBiz = computed(() => !!props.bizId)
|
|
const lockBiz = computed(() => !!props.bizId)
|
|
|
const lockTemplate = computed(() => !!props.templateId)
|
|
const lockTemplate = computed(() => !!props.templateId)
|
|
|
const isExisting = computed(() => Number(form.biz_id) > 0)
|
|
const isExisting = computed(() => Number(form.biz_id) > 0)
|
|
|
-const bizOptions = computed(() => (form.biz_type === 'product' ? products.value : workorders.value))
|
|
|
|
|
const plateTotal = computed(() => sheetCount(form.qty, form.sheet_qty))
|
|
const plateTotal = computed(() => sheetCount(form.qty, form.sheet_qty))
|
|
|
const plateMax = computed(() => Math.max(1, plateTotal.value || 1))
|
|
const plateMax = computed(() => Math.max(1, plateTotal.value || 1))
|
|
|
const sheetHint = computed(() => sheetCountText(form.qty, form.sheet_qty))
|
|
const sheetHint = computed(() => sheetCountText(form.qty, form.sheet_qty))
|
|
@@ -216,13 +219,6 @@ const selectedCover = computed(() => {
|
|
|
})
|
|
})
|
|
|
const selectedCells = computed(() => cellsOf(selectedTemplate.value))
|
|
const selectedCells = computed(() => cellsOf(selectedTemplate.value))
|
|
|
|
|
|
|
|
-function optionValue(item) {
|
|
|
|
|
- if (form.biz_type === 'workorder') {
|
|
|
|
|
- return item.no || ''
|
|
|
|
|
- }
|
|
|
|
|
- return item.code || item.name || ''
|
|
|
|
|
-}
|
|
|
|
|
-
|
|
|
|
|
function pickName(row, fallback = '') {
|
|
function pickName(row, fallback = '') {
|
|
|
if (!row) {
|
|
if (!row) {
|
|
|
return String(fallback || '').trim()
|
|
return String(fallback || '').trim()
|
|
@@ -232,12 +228,49 @@ function pickName(row, fallback = '') {
|
|
|
).trim()
|
|
).trim()
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
-function optionLabel(item) {
|
|
|
|
|
|
|
+function bizSuggestValue(item) {
|
|
|
|
|
+ if (form.biz_type === 'workorder') {
|
|
|
|
|
+ return String(item.no || '').trim()
|
|
|
|
|
+ }
|
|
|
|
|
+ return String(item.code || item.name || '').trim()
|
|
|
|
|
+}
|
|
|
|
|
+
|
|
|
|
|
+function bizSuggestSubtitle(item) {
|
|
|
if (form.biz_type === 'workorder') {
|
|
if (form.biz_type === 'workorder') {
|
|
|
const name = pickName(item)
|
|
const name = pickName(item)
|
|
|
- return name ? (item.no + ' / ' + name) : (item.no || '')
|
|
|
|
|
|
|
+ const spec = String(item.spec || item.product?.spec || '').trim()
|
|
|
|
|
+ const parts = [name, spec].filter(Boolean)
|
|
|
|
|
+ return parts.join(' · ') || '—'
|
|
|
|
|
+ }
|
|
|
|
|
+ const spec = String(item.spec || '').trim()
|
|
|
|
|
+ return spec ? item.name + ' · ' + spec : (item.name || '—')
|
|
|
|
|
+}
|
|
|
|
|
+
|
|
|
|
|
+function toBizSuggest(item) {
|
|
|
|
|
+ return {
|
|
|
|
|
+ id: item.id,
|
|
|
|
|
+ value: bizSuggestValue(item),
|
|
|
|
|
+ subtitle: bizSuggestSubtitle(item),
|
|
|
|
|
+ raw: item,
|
|
|
|
|
+ }
|
|
|
|
|
+}
|
|
|
|
|
+
|
|
|
|
|
+async function searchBiz(queryString, cb) {
|
|
|
|
|
+ const kw = String(queryString || '').trim()
|
|
|
|
|
+ if (!kw || lockBiz.value) {
|
|
|
|
|
+ cb([])
|
|
|
|
|
+ return
|
|
|
|
|
+ }
|
|
|
|
|
+ bizSearching.value = true
|
|
|
|
|
+ try {
|
|
|
|
|
+ const api = form.biz_type === 'product' ? productList : workorderList
|
|
|
|
|
+ const data = await api({ keyword: kw, limit: 20 })
|
|
|
|
|
+ cb((data.rows || []).map(toBizSuggest).filter((item) => item.value))
|
|
|
|
|
+ } catch {
|
|
|
|
|
+ cb([])
|
|
|
|
|
+ } finally {
|
|
|
|
|
+ bizSearching.value = false
|
|
|
}
|
|
}
|
|
|
- return (item.code || '无编号') + ' / ' + (item.name || '')
|
|
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
function processLabel(row) {
|
|
function processLabel(row) {
|
|
@@ -291,17 +324,6 @@ function applySavedProcesses(list) {
|
|
|
draftProcesses.value = []
|
|
draftProcesses.value = []
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
-function findRowByNo(no) {
|
|
|
|
|
- const key = String(no || '').trim()
|
|
|
|
|
- if (!key) {
|
|
|
|
|
- return null
|
|
|
|
|
- }
|
|
|
|
|
- if (form.biz_type === 'workorder') {
|
|
|
|
|
- return workorders.value.find((item) => String(item.no) === key) || null
|
|
|
|
|
- }
|
|
|
|
|
- return products.value.find((item) => String(item.code) === key || String(item.name) === key) || null
|
|
|
|
|
-}
|
|
|
|
|
-
|
|
|
|
|
function syncPlateRange(prevTotal) {
|
|
function syncPlateRange(prevTotal) {
|
|
|
const n = plateTotal.value
|
|
const n = plateTotal.value
|
|
|
if (!(n > 0)) {
|
|
if (!(n > 0)) {
|
|
@@ -325,6 +347,19 @@ function checkAllProcesses() {
|
|
|
checkedProcessKeys.value = savedProcesses.value.map((_, index) => String(index))
|
|
checkedProcessKeys.value = savedProcesses.value.map((_, index) => String(index))
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
|
|
+function clearBizBinding() {
|
|
|
|
|
+ form.biz_id = ''
|
|
|
|
|
+ boundBizNo.value = ''
|
|
|
|
|
+ savedProcesses.value = []
|
|
|
|
|
+ checkedProcessKeys.value = []
|
|
|
|
|
+ preview.value = null
|
|
|
|
|
+}
|
|
|
|
|
+
|
|
|
|
|
+function resetBizForm() {
|
|
|
|
|
+ clearBizBinding()
|
|
|
|
|
+ draftProcesses.value = []
|
|
|
|
|
+}
|
|
|
|
|
+
|
|
|
function onBizTypeChange() {
|
|
function onBizTypeChange() {
|
|
|
form.biz_id = ''
|
|
form.biz_id = ''
|
|
|
form.no = ''
|
|
form.no = ''
|
|
@@ -333,38 +368,50 @@ function onBizTypeChange() {
|
|
|
form.sheet_qty = ''
|
|
form.sheet_qty = ''
|
|
|
form.sheet_from = 1
|
|
form.sheet_from = 1
|
|
|
form.sheet_to = 1
|
|
form.sheet_to = 1
|
|
|
- savedProcesses.value = []
|
|
|
|
|
- checkedProcessKeys.value = []
|
|
|
|
|
- draftProcesses.value = []
|
|
|
|
|
- preview.value = null
|
|
|
|
|
|
|
+ resetBizForm()
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
-async function onNoChange(val) {
|
|
|
|
|
|
|
+function onBizInput() {
|
|
|
if (syncing.value || lockBiz.value) {
|
|
if (syncing.value || lockBiz.value) {
|
|
|
return
|
|
return
|
|
|
}
|
|
}
|
|
|
- preview.value = null
|
|
|
|
|
- const key = String(val || '').trim()
|
|
|
|
|
- if (!key) {
|
|
|
|
|
- form.biz_id = ''
|
|
|
|
|
- savedProcesses.value = []
|
|
|
|
|
- checkedProcessKeys.value = []
|
|
|
|
|
|
|
+ const no = String(form.no || '').trim()
|
|
|
|
|
+ if (Number(form.biz_id) > 0 && no !== String(boundBizNo.value || '').trim()) {
|
|
|
|
|
+ clearBizBinding()
|
|
|
return
|
|
return
|
|
|
}
|
|
}
|
|
|
- const row = findRowByNo(key)
|
|
|
|
|
- if (row) {
|
|
|
|
|
- await loadBizDetail(row.id)
|
|
|
|
|
|
|
+ if (!form.biz_id) {
|
|
|
|
|
+ preview.value = null
|
|
|
|
|
+ }
|
|
|
|
|
+}
|
|
|
|
|
+
|
|
|
|
|
+function onBizClear() {
|
|
|
|
|
+ if (lockBiz.value) {
|
|
|
return
|
|
return
|
|
|
}
|
|
}
|
|
|
- form.biz_id = ''
|
|
|
|
|
- savedProcesses.value = []
|
|
|
|
|
- checkedProcessKeys.value = []
|
|
|
|
|
|
|
+ form.no = ''
|
|
|
|
|
+ form.name = ''
|
|
|
|
|
+ resetBizForm()
|
|
|
|
|
+}
|
|
|
|
|
+
|
|
|
|
|
+async function onBizPick(item) {
|
|
|
|
|
+ if (syncing.value || lockBiz.value || !item?.id) {
|
|
|
|
|
+ return
|
|
|
|
|
+ }
|
|
|
|
|
+ syncing.value = true
|
|
|
|
|
+ form.no = item.value || form.no
|
|
|
|
|
+ try {
|
|
|
|
|
+ await loadBizDetail(item.id)
|
|
|
|
|
+ } finally {
|
|
|
|
|
+ syncing.value = false
|
|
|
|
|
+ }
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
async function loadBizDetail(id) {
|
|
async function loadBizDetail(id) {
|
|
|
if (!id) {
|
|
if (!id) {
|
|
|
return
|
|
return
|
|
|
}
|
|
}
|
|
|
|
|
+ const wasSyncing = syncing.value
|
|
|
syncing.value = true
|
|
syncing.value = true
|
|
|
try {
|
|
try {
|
|
|
if (form.biz_type === 'workorder') {
|
|
if (form.biz_type === 'workorder') {
|
|
@@ -383,9 +430,11 @@ async function loadBizDetail(id) {
|
|
|
form.name = pickName(row, form.name)
|
|
form.name = pickName(row, form.name)
|
|
|
applySavedProcesses(row.processes || [])
|
|
applySavedProcesses(row.processes || [])
|
|
|
}
|
|
}
|
|
|
|
|
+ boundBizNo.value = String(form.no || '').trim()
|
|
|
|
|
+ draftProcesses.value = []
|
|
|
syncPlateRange()
|
|
syncPlateRange()
|
|
|
} finally {
|
|
} finally {
|
|
|
- syncing.value = false
|
|
|
|
|
|
|
+ syncing.value = wasSyncing
|
|
|
}
|
|
}
|
|
|
}
|
|
}
|
|
|
|
|
|
|
@@ -493,22 +542,9 @@ watch(
|
|
|
form.sheet_to = 1
|
|
form.sheet_to = 1
|
|
|
form.copies = 1
|
|
form.copies = 1
|
|
|
try {
|
|
try {
|
|
|
- const [t, w, p] = await Promise.all([
|
|
|
|
|
- templateList({ printable: 1, limit: 100 }),
|
|
|
|
|
- workorderList({ limit: 100 }),
|
|
|
|
|
- productList({ limit: 100 }),
|
|
|
|
|
- ])
|
|
|
|
|
|
|
+ const t = await templateList({ printable: 1, limit: 100 })
|
|
|
templates.value = t.rows || []
|
|
templates.value = t.rows || []
|
|
|
- workorders.value = w.rows || []
|
|
|
|
|
- products.value = p.rows || []
|
|
|
|
|
if (form.biz_id) {
|
|
if (form.biz_id) {
|
|
|
- const listed = (form.biz_type === 'product' ? products.value : workorders.value).find(
|
|
|
|
|
- (item) => Number(item.id) === Number(form.biz_id)
|
|
|
|
|
- )
|
|
|
|
|
- if (listed) {
|
|
|
|
|
- form.no = form.no || (form.biz_type === 'product' ? listed.code : listed.no) || ''
|
|
|
|
|
- form.name = form.name || pickName(listed)
|
|
|
|
|
- }
|
|
|
|
|
await loadBizDetail(form.biz_id)
|
|
await loadBizDetail(form.biz_id)
|
|
|
}
|
|
}
|
|
|
} finally {
|
|
} finally {
|
|
@@ -631,6 +667,26 @@ watch(plateTotal, (n, old) => {
|
|
|
line-height: 1.5;
|
|
line-height: 1.5;
|
|
|
}
|
|
}
|
|
|
.empty-hint { margin: 6px 0 0; color: #c45656; font-size: 12px; }
|
|
.empty-hint { margin: 6px 0 0; color: #c45656; font-size: 12px; }
|
|
|
|
|
+.biz-suggest {
|
|
|
|
|
+ display: flex;
|
|
|
|
|
+ align-items: baseline;
|
|
|
|
|
+ gap: 8px;
|
|
|
|
|
+ line-height: 1.4;
|
|
|
|
|
+ padding: 2px 0;
|
|
|
|
|
+}
|
|
|
|
|
+.biz-suggest-no {
|
|
|
|
|
+ flex-shrink: 0;
|
|
|
|
|
+ font-weight: 600;
|
|
|
|
|
+ color: #1d4f91;
|
|
|
|
|
+}
|
|
|
|
|
+.biz-suggest-name {
|
|
|
|
|
+ flex: 1;
|
|
|
|
|
+ min-width: 0;
|
|
|
|
|
+ color: #606266;
|
|
|
|
|
+ overflow: hidden;
|
|
|
|
|
+ text-overflow: ellipsis;
|
|
|
|
|
+ white-space: nowrap;
|
|
|
|
|
+}
|
|
|
@media (max-width: 960px) {
|
|
@media (max-width: 960px) {
|
|
|
.print-layout { flex-direction: column; }
|
|
.print-layout { flex-direction: column; }
|
|
|
.print-right { width: 100%; }
|
|
.print-right { width: 100%; }
|