feat: 个人用户拜访编辑新增照片查看/删除/上传功能
Co-Authored-By: Claude <noreply@anthropic.com>
This commit is contained in:
@@ -5,6 +5,7 @@ import { useThemeStore } from '@/stores/theme'
|
|||||||
import { customersApi } from '@/api/customers'
|
import { customersApi } from '@/api/customers'
|
||||||
import { ElMessage, ElMessageBox } from 'element-plus'
|
import { ElMessage, ElMessageBox } from 'element-plus'
|
||||||
import { getManagerColor as mgrColorFn, getMgrTextColor, loadManagerColors } from '@/utils/managerColor'
|
import { getManagerColor as mgrColorFn, getMgrTextColor, loadManagerColors } from '@/utils/managerColor'
|
||||||
|
import { compressImage } from '@/utils/image'
|
||||||
import api from '@/api/index'
|
import api from '@/api/index'
|
||||||
|
|
||||||
const auth = useAuthStore()
|
const auth = useAuthStore()
|
||||||
@@ -31,11 +32,49 @@ const indivEditVisible = ref(false)
|
|||||||
const indivEditType = ref('')
|
const indivEditType = ref('')
|
||||||
const indivEditForm = ref<any>({})
|
const indivEditForm = ref<any>({})
|
||||||
const indivEditSaving = ref(false)
|
const indivEditSaving = ref(false)
|
||||||
|
const indivPhotoUrls = ref<Record<string, string>>({})
|
||||||
|
|
||||||
function openIndivEdit(type: string, row: any) {
|
async function openIndivEdit(type: string, row: any) {
|
||||||
indivEditType.value = type
|
indivEditType.value = type
|
||||||
indivEditForm.value = { ...row }
|
indivEditForm.value = { ...row }
|
||||||
indivEditVisible.value = true
|
indivEditVisible.value = true
|
||||||
|
// Load photo URLs for visit editing
|
||||||
|
if (type === 'visit' && row.photos?.length) {
|
||||||
|
for (const key of row.photos) {
|
||||||
|
if (!indivPhotoUrls.value[key]) {
|
||||||
|
try {
|
||||||
|
const urlRes = await api.get('/upload/download-url', { params: { object_key: key } })
|
||||||
|
indivPhotoUrls.value[key] = urlRes.data.download_url
|
||||||
|
} catch (_) { indivPhotoUrls.value[key] = '' }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
async function handleIndivPhotoUpload(event: Event) {
|
||||||
|
const target = event.target as HTMLInputElement
|
||||||
|
if (!target.files?.length) return
|
||||||
|
const form = indivEditForm.value
|
||||||
|
if (!form.photos) form.photos = []
|
||||||
|
if (form.photos.length >= 9) { ElMessage.warning('最多9张照片'); return }
|
||||||
|
for (const file of Array.from(target.files)) {
|
||||||
|
if (form.photos.length >= 9) break
|
||||||
|
try {
|
||||||
|
const compressed = await compressImage(file, { maxPixels: 1920, quality: 0.8 })
|
||||||
|
const presignRes = await api.get('/upload/presigned-url', { params: { filename: compressed.name, content_type: compressed.type || 'image/jpeg' } })
|
||||||
|
await api.put(presignRes.data.upload_url, compressed, { headers: { 'Content-Type': compressed.type || 'image/jpeg' } })
|
||||||
|
form.photos.push(presignRes.data.object_key)
|
||||||
|
indivPhotoUrls.value[presignRes.data.object_key] = URL.createObjectURL(compressed)
|
||||||
|
} catch (_) { ElMessage.error('上传失败') }
|
||||||
|
}
|
||||||
|
target.value = ''
|
||||||
|
}
|
||||||
|
|
||||||
|
function removeIndivPhoto(idx: number) {
|
||||||
|
const form = indivEditForm.value
|
||||||
|
const key = form.photos[idx]
|
||||||
|
delete indivPhotoUrls.value[key]
|
||||||
|
form.photos.splice(idx, 1)
|
||||||
}
|
}
|
||||||
|
|
||||||
async function handleIndivEditSave() {
|
async function handleIndivEditSave() {
|
||||||
@@ -53,6 +92,7 @@ async function handleIndivEditSave() {
|
|||||||
time_range: f.time_range || '',
|
time_range: f.time_range || '',
|
||||||
visit_date: f.visit_date,
|
visit_date: f.visit_date,
|
||||||
manager_id: f.manager_id,
|
manager_id: f.manager_id,
|
||||||
|
photos: f.photos || [],
|
||||||
})
|
})
|
||||||
} else if (type === 'plan') {
|
} else if (type === 'plan') {
|
||||||
await api.put(`/work-plans/${f.id}`, { plan_content: f.plan_content, status: f.status, plan_date: f.plan_date, manager_id: f.manager_id })
|
await api.put(`/work-plans/${f.id}`, { plan_content: f.plan_content, status: f.status, plan_date: f.plan_date, manager_id: f.manager_id })
|
||||||
@@ -710,6 +750,22 @@ async function handleImport() {
|
|||||||
<el-form-item label="相关人员"><el-input v-model="indivEditForm.companion_names_str" placeholder="多个姓名用、分隔" /></el-form-item>
|
<el-form-item label="相关人员"><el-input v-model="indivEditForm.companion_names_str" placeholder="多个姓名用、分隔" /></el-form-item>
|
||||||
<el-form-item label="沟通内容"><el-input v-model="indivEditForm.communication_content" type="textarea" :rows="4" /></el-form-item>
|
<el-form-item label="沟通内容"><el-input v-model="indivEditForm.communication_content" type="textarea" :rows="4" /></el-form-item>
|
||||||
<el-form-item label="客户需求"><el-input v-model="indivEditForm.customer_demand" type="textarea" :rows="2" /></el-form-item>
|
<el-form-item label="客户需求"><el-input v-model="indivEditForm.customer_demand" type="textarea" :rows="2" /></el-form-item>
|
||||||
|
<el-form-item v-if="indivEditForm.photos?.length" label="照片">
|
||||||
|
<div style="display:flex;gap:8px;flex-wrap:wrap">
|
||||||
|
<div v-for="(key, idx) in indivEditForm.photos" :key="key" style="position:relative">
|
||||||
|
<img :src="indivPhotoUrls[key]" style="width:80px;height:80px;object-fit:cover;border:1px solid var(--warm-border)" v-if="indivPhotoUrls[key]" />
|
||||||
|
<span v-else style="width:80px;height:80px;display:flex;align-items:center;justify-content:center;background:var(--paper);border:1px solid var(--warm-border);font-size:12px;color:var(--warm-gray)">加载中</span>
|
||||||
|
<button type="button" style="position:absolute;top:-6px;right:-6px;background:var(--vermilion);color:#fff;border:none;width:18px;height:18px;cursor:pointer;font-size:12px;line-height:1" @click="removeIndivPhoto(idx)">×</button>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</el-form-item>
|
||||||
|
<el-form-item label="添加照片">
|
||||||
|
<label style="cursor:pointer;display:inline-flex;align-items:center;gap:6px;padding:8px 14px;border:1px dashed var(--warm-border);color:var(--warm-gray);font-size:13px">
|
||||||
|
<svg width="16" height="16" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2"><rect x="3" y="3" width="18" height="18" rx="2" ry="2"></rect><circle cx="8.5" cy="8.5" r="1.5"></circle><polyline points="21 15 16 10 5 21"></polyline></svg>
|
||||||
|
上传照片(最多9张)
|
||||||
|
<input type="file" accept="image/*" multiple style="display:none" @change="handleIndivPhotoUpload" />
|
||||||
|
</label>
|
||||||
|
</el-form-item>
|
||||||
</template>
|
</template>
|
||||||
<template v-else-if="indivEditType === 'plan'">
|
<template v-else-if="indivEditType === 'plan'">
|
||||||
<el-form-item label="客户经理">
|
<el-form-item label="客户经理">
|
||||||
|
|||||||
Reference in New Issue
Block a user