feat(wecom): 集成企业微信JSSDK并重构客户信息获取逻辑

refactor(admin): 优化文件上传处理及表单字段管理

fix(user): 修复企微SDK初始化及客户ID获取问题
This commit is contained in:
2026-03-23 16:46:25 +08:00
parent 40c720fdd7
commit 55695da2fd
4 changed files with 267 additions and 92 deletions

View File

@@ -13,6 +13,7 @@
}, },
"dependencies": { "dependencies": {
"@vicons/ionicons5": "^0.13.0", "@vicons/ionicons5": "^0.13.0",
"@wecom/jssdk": "^2.3.4",
"axios": "^1.13.6", "axios": "^1.13.6",
"dev": "^0.1.3", "dev": "^0.1.3",
"naive-ui": "^2.44.1", "naive-ui": "^2.44.1",

8
pnpm-lock.yaml generated
View File

@@ -11,6 +11,9 @@ importers:
'@vicons/ionicons5': '@vicons/ionicons5':
specifier: ^0.13.0 specifier: ^0.13.0
version: 0.13.0 version: 0.13.0
'@wecom/jssdk':
specifier: ^2.3.4
version: 2.3.4
axios: axios:
specifier: ^1.13.6 specifier: ^1.13.6
version: 1.13.6 version: 1.13.6
@@ -650,6 +653,9 @@ packages:
vue: vue:
optional: true optional: true
'@wecom/jssdk@2.3.4':
resolution: {integrity: sha512-oLfuvwMBZCRRMowVi/JkKx/dLNGHCmmUbQfCYG7XGmHYbgkQJlAlack4jKBk+NVG4G0S24fIrAF+XwQuXXxgAw==}
acorn@8.16.0: acorn@8.16.0:
resolution: {integrity: sha512-UVJyE9MttOsBQIDKw1skb9nAwQuR5wuGD3+82K6JgJlm/Y+KI92oNsMNGZCYdDsVtRHSak0pcV5Dno5+4jh9sw==} resolution: {integrity: sha512-UVJyE9MttOsBQIDKw1skb9nAwQuR5wuGD3+82K6JgJlm/Y+KI92oNsMNGZCYdDsVtRHSak0pcV5Dno5+4jh9sw==}
engines: {node: '>=0.4.0'} engines: {node: '>=0.4.0'}
@@ -1890,6 +1896,8 @@ snapshots:
typescript: 5.9.3 typescript: 5.9.3
vue: 3.5.30(typescript@5.9.3) vue: 3.5.30(typescript@5.9.3)
'@wecom/jssdk@2.3.4': {}
acorn@8.16.0: {} acorn@8.16.0: {}
alien-signals@3.1.2: {} alien-signals@3.1.2: {}

View File

@@ -101,9 +101,9 @@
</n-card> </n-card>
</main> </main>
<!-- 详情抽屉 - 视觉重构 --> <!-- 详情抽屉 -->
<n-drawer v-model:show="showDrawer" :width="650" placement="right" resizable> <n-drawer v-model:show="showDrawer" :width="650" placement="right" resizable>
<n-drawer-content title="原始提报资料详情" closable class="modern-drawer"> <n-drawer-content title="原始提报资料详情与分配" closable class="modern-drawer">
<div class="drawer-body" v-if="showDrawer && editingRow.wecom_id"> <div class="drawer-body" v-if="showDrawer && editingRow.wecom_id">
<n-space vertical :size="24"> <n-space vertical :size="24">
<!-- 分配任务卡片 --> <!-- 分配任务卡片 -->
@@ -136,14 +136,8 @@
</div> </div>
<n-form label-placement="left" label-width="90" size="small" :model="editingRow"> <n-form label-placement="left" label-width="90" size="small" :model="editingRow">
<n-grid :x-gap="20" :cols="2"> <n-grid :x-gap="20" :cols="2">
<n-grid-item v-for="field in [ <!-- 修复了之前的 v-for 报错,将数组抽离为了 baseInfoFields -->
{label:'主管', key:'analyst_supervisor'}, <n-grid-item v-for="field in baseInfoFields" :key="field.key">
{label:'部门', key:'analyst_department'},
{label:'分析师', key:'analyst_name'},
{label:'家长姓名', key:'parent_name'},
{label:'家长电话', key:'parent_phone'},
{label:'身份证', key:'parent_id_card'},
]" :key="field.key">
<n-form-item :label="field.label"> <n-form-item :label="field.label">
<n-input v-model:value="editingRow[field.key]" /> <n-input v-model:value="editingRow[field.key]" />
</n-form-item> </n-form-item>
@@ -162,27 +156,43 @@
</n-form> </n-form>
</div> </div>
<!-- 附件区 --> <!-- 附件/素材区 -->
<div class="file-grid"> <div class="file-grid">
<!-- 1. 附件文档 -->
<div class="file-item"> <div class="file-item">
<div class="file-label"><n-icon><FileTrayOutline /></n-icon> 附件文档</div> <div class="file-label"><n-icon><FileTrayOutline /></n-icon> 附件文档</div>
<n-upload <n-upload
v-model:file-list="editingRow.attachmentFileList" v-model:file-list="editingRow.attachmentFileList"
:max="1" :max="1"
:custom-request="({ file, onFinish, onError, onProgress }) => handleCustomUpload({ file, onFinish, onError, onProgress }, 'attachmentFileList')" :custom-request="handleCustomUpload"
> >
<n-button dashed block>上传新附件</n-button> <n-button dashed block>更换附件文档</n-button>
</n-upload> </n-upload>
</div> </div>
<!-- 2. 电子签名 -->
<div class="file-item"> <div class="file-item">
<div class="file-label"><n-icon><ImagesOutline /></n-icon> 付款截图</div> <div class="file-label"><n-icon><CreateOutline /></n-icon> 电子签名</div>
<n-upload
v-model:file-list="editingRow.signatureFileList"
list-type="image-card"
:max="1"
@preview="handlePreview"
:custom-request="handleCustomUpload"
>
点击上传
</n-upload>
</div>
<!-- 3. 付款截图 -->
<div class="file-item payment-item">
<div class="file-label"><n-icon><ImagesOutline /></n-icon> 付款截图凭证 (多选)</div>
<n-upload <n-upload
v-model:file-list="editingRow.paymentFileList" v-model:file-list="editingRow.paymentFileList"
list-type="image-card" list-type="image-card"
multiple multiple
@preview="handlePreview" @preview="handlePreview"
:custom-request="({ file, onFinish, onError, onProgress }) => handleCustomUpload({ file, onFinish, onError, onProgress }, 'paymentFileList')" :custom-request="handleCustomUpload"
/> />
</div> </div>
</div> </div>
@@ -208,21 +218,17 @@
</template> </template>
<script setup> <script setup>
/**
* Script 部分保持原样,无需修改逻辑
* 这里省略重复的逻辑代码以减少篇幅,请直接沿用你原文件中的 script 内容
*/
import { ref, h, reactive, onMounted } from 'vue' import { ref, h, reactive, onMounted } from 'vue'
import { useRouter } from 'vue-router' import { useRouter } from 'vue-router'
import { import {
useMessage, zhCN, dateZhCN, NConfigProvider, NCard, NDataTable, NButton, NIcon, NInput, useMessage, zhCN, dateZhCN, NConfigProvider, NCard, NDataTable, NButton, NIcon, NInput,
NDrawer, NDrawerContent, NSpace, NForm, NFormItem, NGrid, NGridItem, NDatePicker, NSelect, NDrawer, NDrawerContent, NSpace, NForm, NFormItem, NGrid, NGridItem, NDatePicker, NSelect,
NTag, NUpload, NModal, NText, NBadge NTag, NUpload, NModal, NBadge
} from 'naive-ui' } from 'naive-ui'
import { import {
SearchOutline, LogOutOutline, DownloadOutline, PersonOutline, FileTrayOutline, SearchOutline, LogOutOutline, DownloadOutline, PersonOutline, FileTrayOutline,
ImagesOutline, BrushOutline, ReaderOutline, EyeOutline ImagesOutline, BrushOutline, ReaderOutline, EyeOutline, CreateOutline
} from '@vicons/ionicons5' } from '@vicons/ionicons5'
import http from '@/utils/http' import http from '@/utils/http'
@@ -231,6 +237,16 @@ const message = useMessage()
const loading = ref(false) const loading = ref(false)
const submitLoading = ref(false) const submitLoading = ref(false)
// 基础信息表单配置(解决模板中 v-for 太长和语法报错的问题)
const baseInfoFields =[
{ label: '主管', key: 'analyst_supervisor' },
{ label: '部门', key: 'analyst_department' },
{ label: '分析师', key: 'analyst_name' },
{ label: '家长姓名', key: 'parent_name' },
{ label: '家长电话', key: 'parent_phone' },
{ label: '身份证', key: 'parent_id_card' }
]
const searchParams = reactive({ const searchParams = reactive({
wecom_id: '', wecom_id: '',
parentInfo: '', parentInfo: '',
@@ -262,6 +278,9 @@ const pagination = reactive({
} }
}) })
/**
* 核心逻辑:数据请求与文件对象标准化
*/
const fetchData = async () => { const fetchData = async () => {
loading.value = true loading.value = true
try { try {
@@ -278,18 +297,22 @@ const fetchData = async () => {
query.append('start_date', startDate) query.append('start_date', startDate)
query.append('end_date', endDate) query.append('end_date', endDate)
} }
const res = await http.get(`/v1/customer/list?${query.toString()}`) const res = await http.get(`/v1/customer/list?${query.toString()}`)
if (res && res.success) { if (res && res.success) {
displayData.value = res.data.map(item => { displayData.value = res.data.map(item => {
// 列表回显处理:为了让 n-upload 正常显示缩略图,仍然必须组装包含 url 字段的对象
const p_names = Array.isArray(item.payment_object_names) ? item.payment_object_names :[] const p_names = Array.isArray(item.payment_object_names) ? item.payment_object_names :[]
const p_urls = item.payment_image_url ||[] const p_urls = item.payment_image_url ||[]
const paymentFileList = p_urls.map((url, i) => ({ const paymentFileList = p_urls.map((url, i) => ({
id: p_names[i] || `pay_${i}`, id: p_names[i] || `pay_${i}`,
name: `付款截图_${i + 1}.png`, name: `付款截图_${i + 1}.png`,
status: 'finished', status: 'finished',
url: url, url: url, // 映射到组件的 url 以展示缩略图
object_name: p_names[i] object_name: p_names[i] // 保留真实的 object_name
})) }))
// 处理签名
const signatureFileList = item.signature_image_url ?[{ const signatureFileList = item.signature_image_url ?[{
id: item.signature_object_name || 'sig', id: item.signature_object_name || 'sig',
name: '电子签名.png', name: '电子签名.png',
@@ -297,6 +320,8 @@ const fetchData = async () => {
url: item.signature_image_url, url: item.signature_image_url,
object_name: item.signature_object_name object_name: item.signature_object_name
}] :[] }] :[]
// 处理附件文档
const attachmentFileList = item.attachment_file_url ?[{ const attachmentFileList = item.attachment_file_url ?[{
id: item.attachment_object_name || 'att', id: item.attachment_object_name || 'att',
name: '原始附件文档', name: '原始附件文档',
@@ -304,6 +329,7 @@ const fetchData = async () => {
url: item.attachment_file_url, url: item.attachment_file_url,
object_name: item.attachment_object_name object_name: item.attachment_object_name
}] :[] }] :[]
return { return {
...item, ...item,
transaction_amount: item.transaction_amount || '0', transaction_amount: item.transaction_amount || '0',
@@ -318,54 +344,85 @@ const fetchData = async () => {
pagination.itemCount = res.pagination?.total || 0 pagination.itemCount = res.pagination?.total || 0
} }
} catch (error) { } catch (error) {
console.error(error) console.error('Fetch error:', error)
} finally { } finally {
loading.value = false loading.value = false
} }
} }
const handleCustomUpload = async ({ file, onFinish, onError, onProgress }, type) => { /**
* 核心上传逻辑:基于引用的响应式更新 (已适配最新接口格式)
*/
const handleCustomUpload = async ({ file, onFinish, onError, onProgress }) => {
try { try {
const uploadData = new FormData() const uploadData = new FormData()
uploadData.append('file', file.file) uploadData.append('file', file.file)
const response = await http.post('/v1/material/upload', uploadData, { const response = await http.post('/v1/material/upload', uploadData, {
headers: { 'Content-Type': 'multipart/form-data' }, headers: { 'Content-Type': 'multipart/form-data' },
onUploadProgress: (p) => onProgress({ percent: Math.ceil((p.loaded / p.total) * 100) }) onUploadProgress: (p) => onProgress({ percent: Math.ceil((p.loaded / p.total) * 100) })
}) })
if (response && response.success) {
file.rawResponse = response // 提取接口返回的真实数据对象
file.url = response.url const resData = response.data
console.log(24536,resData)
// 判断是否成功获取到了关键字段 object_name
if ( resData && resData.object_name) {
// 1. 核心业务字段赋值:供后续 submitAssignment 提取上传
file.name = resData.object_name
// 2. 组件渲染依赖字段映射Naive UI 组件强依赖 url 属性显示图片预览,所以把 preview_url 给它
file.url = resData.preview_url
// 3. 存储其余接口返回数据:备用
file.download_url = resData.download_url
file.upload_time = resData.upload_time
// 更新组件内部状态为完成
file.status = 'finished' file.status = 'finished'
message.success('上传成功') message.success('上传成功')
onFinish() onFinish()
} else { } else {
message.error(response.message || '上传失败,接口返回数据格式异常')
onError() onError()
} }
} catch (error) { } catch (error) {
console.error('Upload error:', error)
message.error('网络错误,上传失败')
onError() onError()
} }
} }
const getObjectName = (fileItem) => { /**
if (fileItem.rawResponse) return fileItem.rawResponse.data?.object_name || fileItem.rawResponse.object_name || null * 提交分配任务 (包含文件标识符提取)
return fileItem.object_name || null */
}
const submitAssignment = async (row) => { const submitAssignment = async (row) => {
if (!row.assignee_name || !row.assignee_phone) { if (!row.assignee_name || !row.assignee_phone) {
message.warning('请填写指导师姓名和电话') message.warning('请填写指导师姓名和电话')
return false return false
} }
// 检查上传状态
const allFiles = [...row.paymentFileList, ...row.signatureFileList, ...row.attachmentFileList]
if (allFiles.some(f => f.status === 'uploading')) {
message.warning('文件正在上传中,请稍后提交')
return false
}
row.isSubmitting = true row.isSubmitting = true
try { try {
const payment_object_names = row.paymentFileList.map(getObjectName).filter(Boolean) // 从当前数组提取最新的 object_name
const signature_object_name = row.signatureFileList.length > 0 ? getObjectName(row.signatureFileList[0]) : '' const payment_object_names = row.paymentFileList.map(f => f.name || f?.object_name || f.name).filter(Boolean)
const attachment_object_name = row.attachmentFileList.length > 0 ? getObjectName(row.attachmentFileList[0]) : '' const signature_object_name = row.signatureFileList[0]?.name || row.signatureFileList[0]?.object_name || row.signatureFileList[0]?.name
const attachment_object_name = row.attachmentFileList[0]?.name || row.attachmentFileList[0]?.object_name || row.attachmentFileList[0]?.name
const payload = { const payload = {
wecom_id: String(row.wecom_id), wecom_id: String(row.wecom_id),
payment_object_names: payment_object_names, payment_object_names,
signature_object_name: signature_object_name, signature_object_name,
attachment_object_name: attachment_object_name, attachment_object_name,
analyst_supervisor: row.analyst_supervisor, analyst_supervisor: row.analyst_supervisor,
analyst_department: row.analyst_department, analyst_department: row.analyst_department,
analyst_name: row.analyst_name, analyst_name: row.analyst_name,
@@ -378,14 +435,18 @@ const submitAssignment = async (row) => {
assignee_name: row.assignee_name, assignee_name: row.assignee_name,
assignee_phone: row.assignee_phone assignee_phone: row.assignee_phone
} }
console.log(24531221126,row)
console.log('提交的数据:', payload)
const res = await http.post('/v1/material/submit', payload) const res = await http.post('/v1/material/submit', payload)
if (res && (res.success || res.code === 200)) { if (res && (res.success || res.code === 200)) {
message.success('分配成功') message.success('分配并同步成功')
row.status = 'processed' row.status = 'processed'
return true return true
} }
return false return false
} catch (error) { } catch (error) {
console.error('Submit error:', error)
return false return false
} finally { } finally {
row.isSubmitting = false row.isSubmitting = false
@@ -397,12 +458,14 @@ const editingRow = ref({})
const showPreview = ref(false) const showPreview = ref(false)
const previewImageUrl = ref('') const previewImageUrl = ref('')
/**
* 打开详情并执行深拷贝隔离
*/
const openDetails = (row) => { const openDetails = (row) => {
const rowCopy = JSON.parse(JSON.stringify(row)) editingRow.value = JSON.parse(JSON.stringify(row))
if (!rowCopy.transaction_date) { if (!editingRow.value.transaction_date) {
rowCopy.transaction_date = null editingRow.value.transaction_date = null
} }
editingRow.value = rowCopy
showDrawer.value = true showDrawer.value = true
} }
@@ -416,6 +479,9 @@ const handleDrawerSubmit = async () => {
} }
} }
/**
* 表格列配置
*/
const columns =[ const columns =[
{ title: '分析师', key: 'analyst_name', width: 100, fixed: 'left' }, { title: '分析师', key: 'analyst_name', width: 100, fixed: 'left' },
{ title: '家长姓名', key: 'parent_name', width: 100 }, { title: '家长姓名', key: 'parent_name', width: 100 },
@@ -485,6 +551,7 @@ const columns =[
} }
] ]
// 预览依然取 url因为 handleCustomUpload 已将接口真实的 preview_url 映射给了 url
const handlePreview = (file) => { const handlePreview = (file) => {
previewImageUrl.value = file.url || (file.file && URL.createObjectURL(file.file)) previewImageUrl.value = file.url || (file.file && URL.createObjectURL(file.file))
showPreview.value = true showPreview.value = true
@@ -668,6 +735,7 @@ const logout = () => {
font-size: 16px; font-size: 16px;
} }
/* 文件网格布局 */
.file-grid { .file-grid {
display: grid; display: grid;
grid-template-columns: 1fr 1fr; grid-template-columns: 1fr 1fr;
@@ -679,6 +747,13 @@ const logout = () => {
padding: 16px; padding: 16px;
border-radius: 12px; border-radius: 12px;
border: 1px dashed #cbd5e1; border: 1px dashed #cbd5e1;
display: flex;
flex-direction: column;
}
/* 付款截图独占一行 */
.payment-item {
grid-column: span 2;
} }
.file-label { .file-label {
@@ -688,6 +763,7 @@ const logout = () => {
display: flex; display: flex;
align-items: center; align-items: center;
gap: 6px; gap: 6px;
color: #475569;
} }
.drawer-footer { .drawer-footer {
@@ -713,6 +789,10 @@ const logout = () => {
grid-template-columns: 1fr; grid-template-columns: 1fr;
} }
.payment-item {
grid-column: span 1;
}
.content-wrapper { .content-wrapper {
padding: 12px; padding: 12px;
} }

View File

@@ -186,17 +186,26 @@ import {
NForm, NFormItem, NInput, NInputNumber, NDatePicker, NUpload, NUploadDragger, NForm, NFormItem, NInput, NInputNumber, NDatePicker, NUpload, NUploadDragger,
NButton, NIcon, NText, NP NButton, NIcon, NText, NP
} from 'naive-ui' } from 'naive-ui'
import { import {
AnalyticsOutline, LogOutOutline, IdCardOutline, DocumentAttachOutline, AnalyticsOutline, LogOutOutline, IdCardOutline, DocumentAttachOutline,
ImagesOutline, BrushOutline, CloudUploadOutline, CameraOutline, ImagesOutline, BrushOutline, CloudUploadOutline, CameraOutline,
CreateOutline, CloseOutline, CheckmarkCircleOutline CreateOutline, CloseOutline, CheckmarkCircleOutline
} from '@vicons/ionicons5' } from '@vicons/ionicons5'
import http from '@/utils/http' import http from '@/utils/http'
import * as ww from '@wecom/jssdk'
const message = useMessage()
const router = useRouter()
const formRef = ref(null)
// 【修复 1】添加 isWWReady 响应式变量的声明
const isWWReady = ref(false)
// 【修复 2 & 3】使用 let 声明 wecomId并且不在顶层作用域立即调用 API
let wecomId = ''
/** /**
* 主题定制:优化圆角和品牌色 * 主题定制
*/ */
const themeOverrides = { const themeOverrides = {
common: { common: {
@@ -207,15 +216,64 @@ const themeOverrides = {
} }
} }
const message = useMessage() /**
const route = useRoute() * 初始化企业微信 JSSDK
const router = useRouter() */
const formRef = ref(null) async function getConfigSignature(url) {
const response = await fetch('https://superdata.nycjy.cn/api/v1/wecom/agent-config-signature', {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify({ url })
})
const ConfigSignature = await response.json()
console.log('基础签名响应:', ConfigSignature)
if (ConfigSignature.code === 200 && ConfigSignature.data) {
return {
timestamp: ConfigSignature.data.timestamp,
nonceStr: ConfigSignature.data.nonceStr,
signature: ConfigSignature.data.corpSignature
}
}
throw new Error('基础签名获取失败')
}
// 保持原逻辑:获取 wecom_id async function getAgentConfigSignature(url) {
const wecomId = route.query.wecom_id || 'wmcr-ECwAAzKclEfIKNcVgOdxD-TcqLg' const response = await fetch('https://superdata.nycjy.cn/api/v1/wecom/agent-config-signature', {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify({ url })
})
const AgentConfigSignature = await response.json()
console.log('应用签名响应:', AgentConfigSignature)
if (AgentConfigSignature.code === 200 && AgentConfigSignature.data) {
return {
timestamp: AgentConfigSignature.data.timestamp,
nonceStr: AgentConfigSignature.data.nonceStr,
signature: AgentConfigSignature.data.signature
}
}
throw new Error('应用签名获取失败')
}
const initSDK = async () => {
try {
await ww.register({
corpId: 'wwf72acc5a681dca93',
agentId: 1000135,
jsApiList: ['getCurExternalContact'],
getAgentConfigSignature,
getConfigSignature
})
isWWReady.value = true
console.log('企微JSSDK初始化成功')
} catch (e) {
console.error('SDK初始化失败', e)
message.error('企业微信SDK初始化失败请检查配置或环境')
}
}
// 保持原逻辑:响应式表单数据 /**
* 响应式表单数据
*/
const formData = reactive({ const formData = reactive({
analystSupervisor: '', analystSupervisor: '',
analystDepartment: '', analystDepartment: '',
@@ -232,12 +290,16 @@ const formData = reactive({
signatureFileList: [] signatureFileList: []
}) })
// 保持原逻辑:文件预览列表 /**
* 文件预览列表
*/
const documentFileListLast = ref([]) const documentFileListLast = ref([])
const paymentFileListLast = ref([]) const paymentFileListLast = ref([])
const signatureFileListLast = ref([]) const signatureFileListLast = ref([])
// 保持原逻辑:校验规则 /**
* 表单校验规则
*/
const rules = { const rules = {
analystSupervisor: { required: true, message: '请输入主管姓名', trigger: 'blur' }, analystSupervisor: { required: true, message: '请输入主管姓名', trigger: 'blur' },
parentName: { required: true, message: '请输入家长姓名', trigger: 'blur' }, parentName: { required: true, message: '请输入家长姓名', trigger: 'blur' },
@@ -245,7 +307,7 @@ const rules = {
} }
/** /**
* 保持原逻辑:格式化日期 * 格式化日期
*/ */
const formatDate = (timestamp) => { const formatDate = (timestamp) => {
if (!timestamp) return null; if (!timestamp) return null;
@@ -257,7 +319,7 @@ const formatDate = (timestamp) => {
}; };
/** /**
* 保持原逻辑:通用文件上传逻辑 * 通用文件上传逻辑
*/ */
const handleCustomUpload = async ({ file, onFinish, onError, onProgress }, type) => { const handleCustomUpload = async ({ file, onFinish, onError, onProgress }, type) => {
try { try {
@@ -294,60 +356,84 @@ const handleCustomUpload = async ({ file, onFinish, onError, onProgress }, type)
} }
/** /**
* 保持原逻辑:初始化数据回显 * 初始化数据回显
*/ */
const initData = async () => { const initData = async () => {
try { try {
const res = await http.get('/v1/customer/get_customers_info', { wecom_id: wecomId }) // 【修复 3】确保在 SDK ready 后再调用 API
if (isWWReady.value) {
const contactRes = await ww.getCurExternalContact()
wecomId = contactRes?.userId || ''
formData.analystName = res.analystName if (!wecomId) {
formData.parentName = res.customerName message.warning('未获取到当前客户ID请确认在企微侧边栏打开');
formData.parentPhone = res.customerPhone return;
formData.analystNotes = res.notes }
formData.analystSupervisor = res.analystDepartmentLeader?.[0] || ''
formData.analystDepartment = res.analystDepartmentName?.[0] || ''
if (res.dealAmount) formData.transactionAmount = Number(res.dealAmount)
if (res.dealDate) formData.transactionDate = new Date(res.dealDate).getTime()
if (res.proofOfPayment && res.proofOfPayment_urls) { console.log('当前客户 wecom_id:', wecomId);
const paymentFiles = res.proofOfPayment.map((objName, index) => ({ const res = await http.get('/v1/customer/get_customers_info', { wecom_id: wecomId })
id: objName,
name: `凭证-${index + 1}`, formData.analystName = res.analystName
status: 'finished', formData.parentName = res.customerName
url: res.proofOfPayment_urls[index], formData.parentPhone = res.customerPhone
rawResponse: { formData.analystNotes = res.notes
data: { formData.analystSupervisor = res.analystDepartmentLeader?.[0] || ''
object_name: objName, formData.analystDepartment = res.analystDepartmentName?.[0] || ''
url: res.proofOfPayment_urls[index], if (res.dealAmount) formData.transactionAmount = Number(res.dealAmount)
}, if (res.dealDate) formData.transactionDate = new Date(res.dealDate).getTime()
success: true
} if (res.proofOfPayment && res.proofOfPayment_urls) {
})) const paymentFiles = res.proofOfPayment.map((objName, index) => ({
formData.paymentFileList = paymentFiles id: objName,
paymentFileListLast.value = paymentFiles name: `凭证-${index + 1}`,
status: 'finished',
url: res.proofOfPayment_urls[index],
rawResponse: {
data: {
object_name: objName,
url: res.proofOfPayment_urls[index],
},
success: true
}
}))
formData.paymentFileList = paymentFiles
paymentFileListLast.value = paymentFiles
}
message.success('客户数据加载成功')
} }
message.success('数据加载成功')
} catch (error) { } catch (error) {
console.error('加载错误:', error) console.error('加载客户数据错误:', error)
message.error('客户信息加载失败') message.error('客户信息加载失败,请刷新重试')
} }
} }
onMounted(() => { /**
initData() * 生命周期钩子:组件挂载后执行初始化
*/
onMounted(async () => {
await initSDK() // 等待 SDK 初始化完成
initData() // 然后再去获取业务数据
}) })
/**
* 文件预览
*/
const handlePreview = (file) => { const handlePreview = (file) => {
const url = file.url || file.thumbnailUrl const url = file.url || file.thumbnailUrl
if (url) window.open(url) if (url) window.open(url)
} }
/** /**
* 保持原逻辑:更新提交逻辑 * 提交表单
*/ */
const handleSubmit = () => { const handleSubmit = async () => {
formRef.value?.validate(async (errors) => { formRef.value?.validate(async (errors) => {
if (!errors) { if (!errors) {
if (!wecomId) {
message.error('未获取到客户ID无法提交');
return;
}
const submitPayload = { const submitPayload = {
wecom_id: wecomId, wecom_id: wecomId,
analyst_supervisor: formData.analystSupervisor, analyst_supervisor: formData.analystSupervisor,
@@ -371,7 +457,7 @@ const handleSubmit = () => {
message.error('提交失败,请联系管理员'); message.error('提交失败,请联系管理员');
} }
} else { } else {
message.error('请完善必填信息'); message.error('请检查并完善必填信息');
} }
}); });
}; };