feat: 历史周报+图片预览+照片管理+导入优化+用户合并

新增:
- 历史周报: Dashboard/周报详情支持周选择器翻看往周,归档只读
- 图片预览: 全屏大图(移动端+PC端),点击遮罩关闭
- PC端照片管理: 编辑时可上传/删除照片
- 客户导入改为更新模式: 重名自动更新信息,显示操作明细
- 导入跳过原因: 旧周报导入也显示每条跳过原因

优化:
- 填报进度权限: 经理只看到自己,支局长/领导看全员
- 客户经理暖灰色hash标签列
- 用户去重合并(4组),数据完整迁移
- CLAUDE.md 更新到最新状态

Co-Authored-By: Claude <noreply@anthropic.com>
This commit is contained in:
2026-06-23 16:59:31 +08:00
parent 8926475b20
commit aa3fbca710
15 changed files with 323 additions and 74 deletions
+16 -1
View File
@@ -34,6 +34,8 @@ const customers = ref<any[]>([])
const managers = ref<any[]>([])
const uploadedPhotos = ref<string[]>([])
const photoPreviews = ref<string[]>([])
const previewDialogVisible = ref(false)
const previewImageUrl = ref('')
const uploading = ref(false)
const customerSearch = ref('')
@@ -136,6 +138,11 @@ function onTimeRangeChange(val: [string, string] | null) {
form.value.time_range = val ? val.join('-') : ''
}
function previewPhoto(url: string) {
previewImageUrl.value = url
previewDialogVisible.value = true
}
function removePhoto(index: number) {
if (index < photoPreviews.value.length) {
URL.revokeObjectURL(photoPreviews.value[index])
@@ -301,7 +308,7 @@ async function handleDelete() {
</template>
<div class="photo-area">
<div v-for="(key, idx) in uploadedPhotos" :key="key" class="photo-item">
<img :src="photoPreviews[idx]" class="photo-thumb" v-if="photoPreviews[idx]" />
<img :src="photoPreviews[idx]" class="photo-thumb" v-if="photoPreviews[idx]" @click.stop="previewPhoto(photoPreviews[idx])" />
<span class="photo-label">照片{{ idx + 1 }}</span>
<button type="button" class="photo-remove-btn" @click="removePhoto(idx)">
<svg width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round">
@@ -338,6 +345,14 @@ async function handleDelete() {
</button>
</div>
</el-form>
<!-- Image Preview Dialog -->
<teleport to="body">
<div v-if="previewDialogVisible" class="image-preview-overlay" @click="previewDialogVisible = false">
<img :src="previewImageUrl" class="image-preview-full" @click.stop />
<button class="image-preview-close" @click="previewDialogVisible = false"></button>
</div>
</teleport>
</div>
</template>