备货单 添加预览 跟进列表分页 审批记录显示问题处理

This commit is contained in:
浅念
2025-11-03 19:01:08 +08:00
parent b527715b3a
commit 58a6732f1b
21 changed files with 1252 additions and 557 deletions
+18 -3
View File
@@ -638,10 +638,25 @@
if (c.type === 'initiator_leader') {
group.users = []
} else if (c.value) {
group.users = String(c.value)
// group.users = String(c.value)
// .split(',')
// .map((v) => Number((v || '').trim()))
// .filter((n) => !Number.isNaN(n))
const values = String(c.value)
.split(',')
.map((v) => Number((v || '').trim()))
.filter((n) => !Number.isNaN(n))
.map((v) => (v || '').trim())
.filter(Boolean)
// 判断是否为纯数字ID
const isNumericIds = values.every(
(v) => !Number.isNaN(Number(v)) && Number.isInteger(Number(v))
)
if (isNumericIds) {
// 如果是数字ID,转换为数字数组
group.users = values.map((v) => Number(v))
} else {
// 如果是字符串名称,保持为字符串数组
group.users = values
}
}
node.ccGroups.push(group)
}
@@ -242,7 +242,7 @@
const processFiles = (files: any[], type: string) => {
if (!files || !Array.isArray(files)) return []
return files.map((file: any) => ({
name: `${type}文件`,
name: file.original_name,
url: file.file_full_url || file.file_url,
file_name: file.file_url
}))
@@ -937,6 +937,8 @@
pending: h?.status != 'approved' && h?.status != 'rejected' && h?.status != 'submitted',
comment: h?.comment || h?.remark || ''
}))
} else {
approvalRecords.value = []
}
timelineDialogVisible.value = true
}
+3 -1
View File
@@ -335,7 +335,7 @@
const processFiles = (files: any[], type: string) => {
if (!files || !Array.isArray(files)) return []
return files.map((file: any) => ({
name: `${type}文件`,
name: file.original_name,
url: file.file_full_url || file.file_url,
file_name: file.file_url
}))
@@ -499,6 +499,8 @@
pending: h?.status != 'approved' && h?.status != 'rejected' && h?.status != 'submitted',
comment: h?.comment || h?.remark || ''
}))
} else {
approvalRecords.value = []
}
timelineDialogVisible.value = true
}
@@ -275,7 +275,7 @@
const processFiles = (files: any[], type: string) => {
if (!files || !Array.isArray(files)) return []
return files.map((file: any) => ({
name: `${type}文件`,
name: file.original_name,
url: file.file_full_url || file.file_url,
file_name: file.file_url
}))
@@ -499,6 +499,8 @@
pending: h?.status != 'approved' && h?.status != 'rejected' && h?.status != 'submitted',
comment: h?.comment || h?.remark || ''
}))
} else {
approvalRecords.value = []
}
timelineDialogVisible.value = true
}
+1
View File
@@ -60,6 +60,7 @@
<el-table-column prop="name" label="名字" align="center" />
<el-table-column prop="phone" label="电话" align="center" />
<el-table-column prop="email" label="邮箱" align="center" />
<el-table-column prop="report_to_name" label="直属上级" align="center" />
<el-table-column prop="corp_name" label="所属公司" align="center" />
<el-table-column prop="follow" label="状态" align="center">
<template #default="scope">
+1 -1
View File
@@ -82,7 +82,7 @@
<span>{{ account.name }}</span>
</ElOption>
</ElSelect>
</ElFormItem>
</ElFormItem>
<ElFormItem prop="company" label="系统">
<ElSelect v-model="formData.systems" class="account-select" @change="changesystems">
<ElOption
+1 -1
View File
@@ -233,7 +233,7 @@
const processFiles = (files: any[], type: string) => {
if (!files || !Array.isArray(files)) return []
return files.map((file: any) => ({
name: `${type}文件`,
name: file.original_name,
url: file.file_full_url || file.file_url,
file_name: file.file_url
}))
+120 -4
View File
@@ -875,7 +875,13 @@
hint-text="支持多文件上传"
:icon-src="contractIcon"
accept=".jpg,.jpeg,.png,.gif,.pdf,.doc,.docx,.xls,.xlsx,.txt"
@change="(files) => (baseForm.contract = files.map((f) => f.file_name))"
@change="
(files) =>
(baseForm.contract = files.map((f) => ({
url: f.file_name,
original_name: f.name
})))
"
/>
</div>
<!-- 上传PI -->
@@ -890,7 +896,13 @@
hint-text="支持多文件上传"
:icon-src="contractIcon"
accept=".jpg,.jpeg,.png,.gif,.pdf,.doc,.docx,.xls,.xlsx,.txt"
@change="(files) => (baseForm.pi_doc = files.map((f) => f.file_name))"
@change="
(files) =>
(baseForm.pi_doc = files.map((f) => ({
url: f.file_name,
original_name: f.name
})))
"
/>
</div>
<!-- 上传水单 -->
@@ -905,7 +917,13 @@
hint-text="支持多文件上传"
:icon-src="contractIcon"
accept=".jpg,.jpeg,.png,.gif,.pdf,.doc,.docx,.xls,.xlsx,.txt"
@change="(files) => (baseForm.transaction_slip = files.map((f) => f.file_name))"
@change="
(files) =>
(baseForm.transaction_slip = files.map((f) => ({
url: f.file_name,
original_name: f.name
})))
"
/>
</div>
<div class="form-card">
@@ -1039,9 +1057,21 @@
import { useUserStore } from '@/store/modules/user'
import { CrmService } from '@/api/crmApi'
import { useStockingForm } from '@/composables/useStockingForm'
import { onMounted, ref, computed } from 'vue'
import { onMounted, ref, computed, toRaw, watch, onBeforeUnmount } from 'vue'
import MultiFileUpload from '@/components/core/forms/MultiFileUpload.vue'
import contractIcon from '@/assets/img/crm/contract.png'
// 本地草稿缓存(用于切换页面回显,关闭页面时清空)
const STORAGE_VERSION = 'v1'
const userStoreForDraft = useUserStore()
const storageUserId = userStoreForDraft?.info?.userId || 'anonymous'
const draftKeyBase = `stocking:add:draft:${STORAGE_VERSION}:${storageUserId}`
const routeForDraft = useRoute()
const draftKey = computed(() => {
// 若存在复制/编辑 id,区分不同草稿;否则使用路径
const id = routeForDraft.query?.id
return id ? `${draftKeyBase}:${id}` : `${draftKeyBase}:${routeForDraft.fullPath}`
})
defineOptions({ name: 'CrmStockingAdd' }) // 定义组件名称,用于 KeepAlive 缓存控制
@@ -1173,6 +1203,69 @@
handleVehicleCurrentChange,
chooseVehicle
} = useStockingForm(false) // isFinal = false
// ---------- 草稿缓存:保存/恢复/清理 ----------
const DRAFT_DEBOUNCE_MS = 500
let draftTimer: number | any = null
const pickDraftPayload = () => ({
baseForm: toRaw(baseForm),
items: toRaw(items.value),
paymentItems: toRaw(paymentItems.value),
contractFiles: toRaw(contractFiles.value),
piFiles: toRaw(piFiles.value),
waterBillFiles: toRaw(waterBillFiles.value)
})
const saveDraft = () => {
try {
const payload = pickDraftPayload()
localStorage.setItem(draftKey.value, JSON.stringify(payload))
} catch {}
}
const scheduleSaveDraft = () => {
if (draftTimer) clearTimeout(draftTimer)
draftTimer = setTimeout(() => {
saveDraft()
}, DRAFT_DEBOUNCE_MS)
}
const loadDraft = () => {
try {
const raw = localStorage.getItem(draftKey.value)
if (!raw) return
const parsed = JSON.parse(raw)
// 合并到现有表单数据
if (parsed?.baseForm && typeof parsed.baseForm === 'object') {
Object.assign(baseForm, parsed.baseForm)
}
if (Array.isArray(parsed?.items)) {
items.value = parsed.items
}
if (Array.isArray(parsed?.paymentItems)) {
paymentItems.value = parsed.paymentItems
}
if (Array.isArray(parsed?.contractFiles)) {
contractFiles.value = parsed.contractFiles
baseForm.contract = (contractFiles.value || []).map((f: any) => f.file_name)
}
if (Array.isArray(parsed?.piFiles)) {
piFiles.value = parsed.piFiles
baseForm.pi_doc = (piFiles.value || []).map((f: any) => f.file_name)
}
if (Array.isArray(parsed?.waterBillFiles)) {
waterBillFiles.value = parsed.waterBillFiles
baseForm.transaction_slip = (waterBillFiles.value || []).map((f: any) => f.file_name)
}
} catch {}
}
const clearDraft = () => {
try {
localStorage.removeItem(draftKey.value)
} catch {}
}
// 获取详情数据
const getdetilfn = async () => {
const res = await CrmService.getStockDetail({ id: stocking_id })
@@ -1197,6 +1290,8 @@
}
// 如果校验通过,调用原始的handleSubmit方法
await handleSubmit(isFinal)
// 提交成功后清理草稿
clearDraft()
} catch (error) {
console.log('表单校验失败:', error)
}
@@ -1209,6 +1304,27 @@
if (stocking_id) {
await getdetilfn()
}
// 尝试从草稿恢复
loadDraft()
// 监听表单变化,自动保存草稿
watch(
() => [baseForm, items.value, paymentItems.value],
() => scheduleSaveDraft(),
{ deep: true }
)
watch(contractFiles, scheduleSaveDraft, { deep: true })
watch(piFiles, scheduleSaveDraft, { deep: true })
watch(waterBillFiles, scheduleSaveDraft, { deep: true })
// 浏览器标签关闭时清理草稿
const beforeUnload = () => {
clearDraft()
}
window.addEventListener('beforeunload', beforeUnload)
onBeforeUnmount(() => {
window.removeEventListener('beforeunload', beforeUnload)
// 当页面真正被卸载(如关闭当前路由标签)时清理草稿
clearDraft()
})
})
</script>
+21 -5
View File
@@ -866,10 +866,15 @@
hint-text="支持多文件上传"
:icon-src="contractIcon"
accept=".jpg,.jpeg,.png,.gif,.pdf,.doc,.docx,.xls,.xlsx,.txt"
@change="(files) => (baseForm.contract = files.map((f) => f.file_name))"
@change="
(files) =>
(baseForm.contract = files.map((f) => ({
url: f.file_name,
original_name: f.name
})))
"
/>
</div>
<!-- 上传PI -->
<div class="boxshadow">
<div class="form-title">
@@ -882,10 +887,15 @@
hint-text="支持多文件上传"
:icon-src="contractIcon"
accept=".jpg,.jpeg,.png,.gif,.pdf,.doc,.docx,.xls,.xlsx,.txt"
@change="(files) => (baseForm.pi_doc = files.map((f) => f.file_name))"
@change="
(files) =>
(baseForm.pi_doc = files.map((f) => ({
url: f.file_name,
original_name: f.name
})))
"
/>
</div>
<!-- 上传水单 -->
<div class="boxshadow">
<div class="form-title">
@@ -898,7 +908,13 @@
hint-text="支持多文件上传"
:icon-src="contractIcon"
accept=".jpg,.jpeg,.png,.gif,.pdf,.doc,.docx,.xls,.xlsx,.txt"
@change="(files) => (baseForm.transaction_slip = files.map((f) => f.file_name))"
@change="
(files) =>
(baseForm.transaction_slip = files.map((f) => ({
url: f.file_name,
original_name: f.name
})))
"
/>
</div>
<div class="form-card">
+21 -5
View File
@@ -1005,10 +1005,15 @@
hint-text="支持多文件上传"
:icon-src="contractIcon"
accept=".jpg,.jpeg,.png,.gif,.pdf,.doc,.docx,.xls,.xlsx,.txt"
@change="(files) => (baseForm.contract = files.map((f) => f.file_name))"
@change="
(files) =>
(baseForm.contract = files.map((f) => ({
url: f.file_name,
original_name: f.name
})))
"
/>
</div>
<!-- 上传PI -->
<div class="boxshadow">
<div class="form-title">
@@ -1021,10 +1026,15 @@
hint-text="支持多文件上传"
:icon-src="contractIcon"
accept=".jpg,.jpeg,.png,.gif,.pdf,.doc,.docx,.xls,.xlsx,.txt"
@change="(files) => (baseForm.pi_doc = files.map((f) => f.file_name))"
@change="
(files) =>
(baseForm.pi_doc = files.map((f) => ({
url: f.file_name,
original_name: f.name
})))
"
/>
</div>
<!-- 上传水单 -->
<div class="boxshadow">
<div class="form-title">
@@ -1037,7 +1047,13 @@
hint-text="支持多文件上传"
:icon-src="contractIcon"
accept=".jpg,.jpeg,.png,.gif,.pdf,.doc,.docx,.xls,.xlsx,.txt"
@change="(files) => (baseForm.transaction_slip = files.map((f) => f.file_name))"
@change="
(files) =>
(baseForm.transaction_slip = files.map((f) => ({
url: f.file_name,
original_name: f.name
})))
"
/>
</div>
<div class="form-card">
+3 -1
View File
@@ -228,6 +228,8 @@
pending: h?.status != 'approved' && h?.status != 'rejected' && h?.status != 'submitted',
comment: h?.comment || h?.remark || ''
}))
} else {
approvalRecords.value = []
}
timelineDialogVisible.value = true
}
@@ -312,7 +314,7 @@
const processFiles = (files: any[], type: string) => {
if (!files || !Array.isArray(files)) return []
return files.map((file: any) => ({
name: `${type}文件`,
name: file.original_name,
url: file.file_full_url || file.file_url,
file_name: file.file_url
}))
+21 -5
View File
@@ -869,10 +869,15 @@
hint-text="支持多文件上传"
:icon-src="contractIcon"
accept=".jpg,.jpeg,.png,.gif,.pdf,.doc,.docx,.xls,.xlsx,.txt"
@change="(files) => (baseForm.contract = files.map((f) => f.file_name))"
@change="
(files) =>
(baseForm.contract = files.map((f) => ({
url: f.file_name,
original_name: f.name
})))
"
/>
</div>
<!-- 上传PI -->
<div class="boxshadow">
<div class="form-title">
@@ -885,10 +890,15 @@
hint-text="支持多文件上传"
:icon-src="contractIcon"
accept=".jpg,.jpeg,.png,.gif,.pdf,.doc,.docx,.xls,.xlsx,.txt"
@change="(files) => (baseForm.pi_doc = files.map((f) => f.file_name))"
@change="
(files) =>
(baseForm.pi_doc = files.map((f) => ({
url: f.file_name,
original_name: f.name
})))
"
/>
</div>
<!-- 上传水单 -->
<div class="boxshadow">
<div class="form-title">
@@ -901,7 +911,13 @@
hint-text="支持多文件上传"
:icon-src="contractIcon"
accept=".jpg,.jpeg,.png,.gif,.pdf,.doc,.docx,.xls,.xlsx,.txt"
@change="(files) => (baseForm.transaction_slip = files.map((f) => f.file_name))"
@change="
(files) =>
(baseForm.transaction_slip = files.map((f) => ({
url: f.file_name,
original_name: f.name
})))
"
/>
</div>
<div class="form-card">
+4 -2
View File
@@ -148,7 +148,7 @@
<i class="iconfont-sys">&#xe80a;</i> 作废
</el-link>
<el-link
v-if="scope.row.approval_status == 3 || scope.row.approval_status == 4"
v-if="scope.row.approval_status != 1 && scope.row.approval_status != 2"
type="danger"
underline="never"
@click="stockdeletefn(scope.row)"
@@ -293,6 +293,8 @@
pending: h?.status != 'approved' && h?.status != 'rejected' && h?.status != 'submitted',
comment: h?.comment || h?.remark || ''
}))
} else {
approvalRecords.value = []
}
timelineDialogVisible.value = true
}
@@ -389,7 +391,7 @@
const processFiles = (files: any[], type: string) => {
if (!files || !Array.isArray(files)) return []
return files.map((file: any) => ({
name: `${type}文件`,
name: file.original_name,
url: file.file_full_url || file.file_url,
file_name: file.file_url
}))