Files
threeonecheck_web/pages/Idphotomanagement/Idphotomanagement.vue
2026-02-08 09:30:43 +08:00

820 lines
18 KiB
Vue
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

<template>
<view class="page padding">
<!-- 证照列表 -->
<view class="license-list" v-if="licenseList.length > 0">
<view class="license-item" v-for="(item, index) in licenseList" :key="item.id">
<view class="license-info">
<view class="license-header">
<text class="license-type">{{ item.type || '未知类型' }}</text>
<view class="license-actions">
<text class="action-btn text-blue" @click="handleEdit(item)">编辑</text>
<text class="action-btn text-red" @click="handleDelete(item)">删除</text>
</view>
</view>
<view class="license-detail">
<view class="detail-row">
<text class="label">证件编号</text>
<text class="value">{{ item.code || '-' }}</text>
</view>
<view class="detail-row">
<text class="label">有效期</text>
<text class="value">{{ item.startDate || '-' }} {{ item.endDate || '-' }}</text>
</view>
<view class="detail-row">
<text class="label">法人</text>
<text class="value">{{ item.legalPerson || '-' }}</text>
</view>
</view>
<view class="license-photo" v-if="item.photo">
<image :src="getImageUrl(item.photo)" mode="aspectFill" @click="previewImage(item.photo)"></image>
</view>
</view>
</view>
</view>
<!-- 空状态 -->
<view class="empty-state" v-else>
<text class="text-gray text-center">暂无证照记录</text>
</view>
<!-- 新增按钮 -->
<button class="add-btn cuIcon-add bg-blue round" @click="openAddPopup">+ 新增</button>
<!-- 新增/编辑证照弹窗 -->
<u-popup :show="showAddPopup" mode="center" round="20" @close="closePopup">
<view class="popup-content">
<view class="popup-header">
<view class="popup-title text-bold">{{ isEdit ? '编辑证照' : '新增证照' }}</view>
<view class="popup-close" @click="closePopup">×</view>
</view>
<scroll-view class="popup-body" scroll-y>
<!-- 部门 -->
<view class="form-item">
<view class="form-label">部门<text class="text-red">*</text></view>
<view class="form-input form-select" @click="showDeptPopup = true">
<text :class="formData.enterpriseName ? '' : 'text-gray'">
{{ formData.enterpriseName || '请选择部门' }}
</text>
</view>
</view>
<!-- 证件类型 -->
<view class="form-item">
<view class="form-label">证件类型</view>
<input class="form-input" v-model="formData.type" placeholder="请输入证件类型" />
</view>
<!-- 证件编号 -->
<view class="form-item">
<view class="form-label">证件编号</view>
<input class="form-input" v-model="formData.code" placeholder="请输入证件编号" />
</view>
<!-- 开始日期 -->
<view class="form-item">
<view class="form-label">开始日期</view>
<view class="form-input form-select" @click="openDatePicker('start')">
<text :class="formData.startDate ? '' : 'text-gray'">
{{ formData.startDate || '请选择开始日期' }}
</text>
</view>
</view>
<!-- 结束日期 -->
<view class="form-item">
<view class="form-label">结束日期</view>
<view class="form-input form-select" @click="openDatePicker('end')">
<text :class="formData.endDate ? '' : 'text-gray'">
{{ formData.endDate || '请选择结束日期' }}
</text>
</view>
</view>
<!-- 法人 -->
<view class="form-item">
<view class="form-label">法人</view>
<input class="form-input" v-model="formData.legalPerson" placeholder="请输入法人" />
</view>
<!-- 封面图片 -->
<view class="form-item">
<view class="form-label">封面图片</view>
<view class="upload-box" @click="chooseImage">
<view class="upload-add" v-if="!formData.photoPreview">
<text class="upload-icon">+</text>
<text class="upload-text">上传照片</text>
</view>
<view class="upload-preview" v-else>
<image :src="formData.photoPreview" mode="aspectFill" class="upload-img"></image>
<view class="upload-delete" @click.stop="removeImage">×</view>
</view>
</view>
</view>
</scroll-view>
<view class="popup-footer">
<button class="btn-cancel" @click="closePopup">取消</button>
<button class="btn-confirm bg-blue" @click="handleSubmit" :loading="submitting">确定</button>
</view>
</view>
</u-popup>
<!-- 日期选择器 -->
<u-datetime-picker
:show="showDatePicker"
v-model="datePickerValue"
mode="date"
@confirm="onDateConfirm"
@cancel="onDateCancel"
@close="onDateCancel"
></u-datetime-picker>
<!-- 选择部门弹窗 -->
<u-popup :show="showDeptPopup" mode="center" round="20" @close="showDeptPopup = false">
<view class="dept-popup">
<view class="popup-header">
<view class="popup-title text-bold">选择部门</view>
<view class="popup-close" @click="showDeptPopup = false">×</view>
</view>
<scroll-view class="dept-list" scroll-y v-if="deptList.length > 0">
<view
class="dept-item"
v-for="item in deptList"
:key="item.id"
@click="selectedDept = item"
>
<view class="dept-checkbox" :class="{ 'dept-checkbox-active': selectedDept && selectedDept.id === item.id }">
<text v-if="selectedDept && selectedDept.id === item.id"></text>
</view>
<text class="dept-name">{{ item.name }}</text>
</view>
</scroll-view>
<view class="text-gray text-center padding" v-else>
暂无部门数据
</view>
<button class="btn-dept-confirm bg-blue" @click="confirmDept">确定</button>
</view>
</u-popup>
<!-- 删除确认弹窗 -->
<u-modal
:show="showDeleteModal"
title="确认删除"
content="确定要删除这条证照记录吗?"
showCancelButton
@confirm="confirmDelete"
@cancel="showDeleteModal = false"
></u-modal>
</view>
</template>
<script setup>
import { ref, reactive, onMounted } from 'vue';
import {
getLicenseEnterpriseSelect,
getLicenseList,
getLicenseDetail,
addLicense,
updateLicense,
deleteLicense
} from '@/request/three_one_api/license.js';
import { baseUrl, getToken } from '@/request/request.js';
// 证照列表
const licenseList = ref([]);
// 部门列表
const deptList = ref([]);
const selectedDept = ref(null);
// 弹窗控制
const showAddPopup = ref(false);
const showDatePicker = ref(false);
const showDeptPopup = ref(false);
const showDeleteModal = ref(false);
// 编辑状态
const isEdit = ref(false);
const currentEditId = ref(null);
const currentDeleteItem = ref(null);
const submitting = ref(false);
// 日期选择类型
const datePickerType = ref('start');
// 日期选择器的值(时间戳)
const datePickerValue = ref(Date.now());
// 表单数据
const formData = reactive({
enterpriseId: '',
enterpriseName: '',
type: '',
code: '',
startDate: '',
endDate: '',
legalPerson: '',
photo: '',
photoPreview: ''
});
// 页面加载
onMounted(() => {
loadLicenseList();
loadDeptList();
});
// 获取图片完整URL
const getImageUrl = (path) => {
if (!path) return '';
if (path.startsWith('http')) return path;
return baseUrl + path;
};
// 预览图片
const previewImage = (path) => {
uni.previewImage({
urls: [getImageUrl(path)]
});
};
// 加载证照列表
const loadLicenseList = async () => {
try {
const res = await getLicenseList();
if (res.code === 0) {
licenseList.value = res.data.records || [];
}
} catch (err) {
console.error('获取证照列表失败:', err);
}
};
// 加载部门列表
const loadDeptList = async () => {
try {
const res = await getLicenseEnterpriseSelect();
if (res.code === 0) {
deptList.value = res.data || [];
}
} catch (err) {
console.error('获取部门列表失败:', err);
}
};
// 打开新增弹窗
const openAddPopup = () => {
resetForm();
isEdit.value = false;
currentEditId.value = null;
showAddPopup.value = true;
};
// 编辑证照
const handleEdit = async (item) => {
try {
// 先获取详情
const res = await getLicenseDetail({ id: item.id });
if (res.code === 0) {
const detail = res.data;
isEdit.value = true;
currentEditId.value = item.id;
// 填充表单数据
formData.enterpriseId = detail.enterpriseId || '';
formData.type = detail.type || '';
formData.code = detail.code || '';
formData.startDate = detail.startDate || '';
formData.endDate = detail.endDate || '';
formData.legalPerson = detail.legalPerson || '';
formData.photo = detail.photo || '';
formData.photoPreview = detail.photo ? getImageUrl(detail.photo) : '';
// 设置部门名称
const dept = deptList.value.find(d => d.id === detail.enterpriseId);
formData.enterpriseName = dept ? dept.name : '';
selectedDept.value = dept || null;
showAddPopup.value = true;
}
} catch (err) {
console.error('获取证照详情失败:', err);
uni.showToast({ title: '获取详情失败', icon: 'none' });
}
};
// 删除证照
const handleDelete = (item) => {
currentDeleteItem.value = item;
showDeleteModal.value = true;
};
// 确认删除
const confirmDelete = async () => {
if (!currentDeleteItem.value) return;
try {
const res = await deleteLicense({ id: currentDeleteItem.value.id });
if (res.code === 0) {
uni.showToast({ title: '删除成功', icon: 'success' });
loadLicenseList();
}
} catch (err) {
console.error('删除失败:', err);
uni.showToast({ title: '删除失败', icon: 'none' });
} finally {
showDeleteModal.value = false;
currentDeleteItem.value = null;
}
};
// 关闭弹窗
const closePopup = () => {
showAddPopup.value = false;
resetForm();
};
// 重置表单
const resetForm = () => {
formData.enterpriseId = '';
formData.enterpriseName = '';
formData.type = '';
formData.code = '';
formData.startDate = '';
formData.endDate = '';
formData.legalPerson = '';
formData.photo = '';
formData.photoPreview = '';
selectedDept.value = null;
isEdit.value = false;
currentEditId.value = null;
};
// 确认选择部门
const confirmDept = () => {
if (selectedDept.value) {
formData.enterpriseId = selectedDept.value.id;
formData.enterpriseName = selectedDept.value.name;
}
showDeptPopup.value = false;
};
// 打开日期选择器
const openDatePicker = (type) => {
datePickerType.value = type;
// 根据已有的日期设置选择器初始值
let currentDate = '';
if (type === 'start' && formData.startDate) {
currentDate = formData.startDate;
} else if (type === 'end' && formData.endDate) {
currentDate = formData.endDate;
}
// 如果有已选择的日期,转换为时间戳
if (currentDate) {
datePickerValue.value = new Date(currentDate).getTime();
} else {
datePickerValue.value = Date.now();
}
showDatePicker.value = true;
};
// 日期选择取消/关闭
const onDateCancel = () => {
showDatePicker.value = false;
};
// 日期选择确认
const onDateConfirm = (e) => {
// 使用 v-model 绑定的 datePickerValue
const timestamp = datePickerValue.value;
// 验证时间戳
if (!timestamp || isNaN(timestamp)) {
console.error('无效的日期值:', timestamp);
showDatePicker.value = false;
return;
}
const date = new Date(timestamp);
// 验证日期是否有效
if (isNaN(date.getTime())) {
console.error('无效的日期:', date);
showDatePicker.value = false;
return;
}
const year = date.getFullYear();
const month = String(date.getMonth() + 1).padStart(2, '0');
const day = String(date.getDate()).padStart(2, '0');
const dateStr = `${year}-${month}-${day}`;
if (datePickerType.value === 'start') {
formData.startDate = dateStr;
} else {
formData.endDate = dateStr;
}
showDatePicker.value = false;
};
// 选择图片
const chooseImage = () => {
uni.chooseImage({
count: 1,
sizeType: ['compressed'],
sourceType: ['album', 'camera'],
success: (res) => {
const tempFilePath = res.tempFilePaths[0];
formData.photoPreview = tempFilePath;
// 上传图片
uploadImage(tempFilePath);
}
});
};
// 上传图片
const uploadImage = (filePath) => {
uni.showLoading({ title: '上传中...' });
uni.uploadFile({
url: baseUrl + '/frontend/attachment/upload',
filePath: filePath,
name: 'file',
header: {
'Authorization': getToken()
},
success: (uploadRes) => {
uni.hideLoading();
try {
const data = JSON.parse(uploadRes.data);
if (data.code === 0 && data.data) {
formData.photo = data.data.url || data.data;
uni.showToast({ title: '上传成功', icon: 'success' });
} else {
uni.showToast({ title: data.msg || '上传失败', icon: 'none' });
formData.photoPreview = '';
}
} catch (e) {
console.error('解析上传结果失败:', e);
uni.showToast({ title: '上传失败', icon: 'none' });
formData.photoPreview = '';
}
},
fail: (err) => {
uni.hideLoading();
console.error('上传失败:', err);
uni.showToast({ title: '上传失败', icon: 'none' });
formData.photoPreview = '';
}
});
};
// 移除图片
const removeImage = () => {
formData.photo = '';
formData.photoPreview = '';
};
// 提交表单
const handleSubmit = async () => {
// 表单验证
if (!formData.enterpriseId) {
uni.showToast({ title: '请选择部门', icon: 'none' });
return;
}
submitting.value = true;
try {
const submitData = {
enterpriseId: formData.enterpriseId,
type: formData.type,
code: formData.code,
startDate: formData.startDate,
endDate: formData.endDate,
legalPerson: formData.legalPerson,
photo: formData.photo
};
let res;
if (isEdit.value) {
// 编辑
submitData.id = currentEditId.value;
res = await updateLicense(submitData);
} else {
// 新增
res = await addLicense(submitData);
}
if (res.code === 0) {
uni.showToast({
title: isEdit.value ? '修改成功' : '新增成功',
icon: 'success'
});
closePopup();
loadLicenseList();
}
} catch (err) {
console.error('提交失败:', err);
uni.showToast({ title: '操作失败', icon: 'none' });
} finally {
submitting.value = false;
}
};
</script>
<style lang="scss" scoped>
.page {
min-height: 100vh;
background: #EBF2FC;
padding-bottom: 120rpx;
}
// 证照列表样式
.license-list {
padding-bottom: 20rpx;
}
.license-item {
background: #fff;
border-radius: 16rpx;
padding: 24rpx;
margin-bottom: 20rpx;
box-shadow: 0 2rpx 12rpx rgba(0, 0, 0, 0.05);
}
.license-header {
display: flex;
justify-content: space-between;
align-items: center;
margin-bottom: 16rpx;
padding-bottom: 16rpx;
border-bottom: 1rpx solid #f0f0f0;
}
.license-type {
font-size: 32rpx;
font-weight: bold;
color: #333;
}
.license-actions {
display: flex;
gap: 20rpx;
}
.action-btn {
font-size: 28rpx;
padding: 8rpx 16rpx;
}
.license-detail {
margin-bottom: 16rpx;
}
.detail-row {
display: flex;
margin-bottom: 12rpx;
font-size: 28rpx;
.label {
color: #999;
width: 160rpx;
flex-shrink: 0;
}
.value {
color: #333;
flex: 1;
}
}
.license-photo {
width: 200rpx;
height: 150rpx;
border-radius: 8rpx;
overflow: hidden;
image {
width: 100%;
height: 100%;
}
}
// 空状态
.empty-state {
padding: 200rpx 0;
text-align: center;
}
// 新增按钮
.add-btn {
position: fixed;
bottom: 40rpx;
left: 30rpx;
right: 30rpx;
height: 88rpx;
line-height: 88rpx;
border-radius: 44rpx;
font-size: 32rpx;
}
// 弹出框样式
.popup-content {
width: 600rpx;
background: #fff;
border-radius: 20rpx;
padding: 30rpx;
}
.popup-header {
display: flex;
justify-content: space-between;
align-items: center;
margin-bottom: 30rpx;
}
.popup-title {
font-size: 34rpx;
color: #333;
}
.popup-close {
font-size: 48rpx;
color: #999;
line-height: 1;
}
.popup-body {
max-height: 700rpx;
overflow-y: auto;
}
.form-item {
margin-bottom: 24rpx;
}
.form-label {
font-size: 28rpx;
color: #333;
margin-bottom: 12rpx;
}
.form-input {
width: 100%;
height: 80rpx;
border: 2rpx solid #E5E5E5;
border-radius: 12rpx;
padding: 0 24rpx;
font-size: 28rpx;
box-sizing: border-box;
}
.form-select {
display: flex;
align-items: center;
line-height: 80rpx;
}
.upload-box {
width: 200rpx;
height: 200rpx;
border: 2rpx dashed #ccc;
border-radius: 12rpx;
display: flex;
align-items: center;
justify-content: center;
position: relative;
}
.upload-add {
display: flex;
flex-direction: column;
align-items: center;
}
.upload-icon {
font-size: 60rpx;
color: #999;
}
.upload-text {
font-size: 24rpx;
color: #999;
margin-top: 8rpx;
}
.upload-preview {
width: 100%;
height: 100%;
position: relative;
}
.upload-img {
width: 100%;
height: 100%;
border-radius: 12rpx;
}
.upload-delete {
position: absolute;
top: -16rpx;
right: -16rpx;
width: 40rpx;
height: 40rpx;
background: #ff4d4f;
color: #fff;
border-radius: 50%;
display: flex;
align-items: center;
justify-content: center;
font-size: 28rpx;
}
.popup-footer {
display: flex;
justify-content: center;
gap: 30rpx;
margin-top: 40rpx;
}
.btn-cancel {
flex: 1;
height: 80rpx;
line-height: 80rpx;
border: 2rpx solid #E5E5E5;
border-radius: 40rpx;
background: #fff;
color: #333;
font-size: 30rpx;
}
.btn-confirm {
flex: 1;
height: 80rpx;
line-height: 80rpx;
border-radius: 40rpx;
color: #fff;
font-size: 30rpx;
}
// 部门选择弹窗
.dept-popup {
width: 600rpx;
background: #fff;
border-radius: 20rpx;
padding: 30rpx;
}
.dept-list {
max-height: 400rpx;
overflow-y: auto;
margin-bottom: 30rpx;
}
.dept-item {
display: flex;
align-items: center;
padding: 24rpx;
border: 2rpx solid #E5E5E5;
border-radius: 12rpx;
margin-bottom: 16rpx;
}
.dept-checkbox {
width: 36rpx;
height: 36rpx;
border: 2rpx solid #ccc;
border-radius: 6rpx;
margin-right: 20rpx;
display: flex;
align-items: center;
justify-content: center;
flex-shrink: 0;
}
.dept-checkbox-active {
background: #2667E9;
border-color: #2667E9;
color: #fff;
}
.dept-name {
font-size: 28rpx;
color: #333;
}
.btn-dept-confirm {
width: 100%;
height: 80rpx;
line-height: 80rpx;
border-radius: 40rpx;
color: #fff;
font-size: 30rpx;
}
</style>