基本功能都已完成

This commit is contained in:
王利强
2026-02-08 09:30:43 +08:00
parent 1ad538f351
commit 721ef0ad54
494 changed files with 6837 additions and 42302 deletions

View File

@@ -1,23 +1,60 @@
<template>
<view class="page padding">
<view class="text-gray text-center" v-if="!hasData">暂无证件照记录</view>
<button class="cuIcon-add bg-blue round margin-top-xl" @click="showAddPopup = true">新增</button>
<!-- 证照列表 -->
<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>
<!-- 新增证件照弹窗 -->
<u-popup :show="showAddPopup" mode="center" round="20" @close="showAddPopup = false">
<!-- 空状态 -->
<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">新增证照</view>
<view class="popup-close" @click="showAddPopup = false">×</view>
<view class="popup-title text-bold">{{ isEdit ? '编辑证照' : '新增证照' }}</view>
<view class="popup-close" @click="closePopup">×</view>
</view>
<view class="popup-body">
<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.dept ? '' : 'text-gray'">
{{ formData.dept || '请选择部门' }}
<text :class="formData.enterpriseName ? '' : 'text-gray'">
{{ formData.enterpriseName || '请选择部门' }}
</text>
</view>
</view>
@@ -25,49 +62,60 @@
<!-- 证件类型 -->
<view class="form-item">
<view class="form-label">证件类型</view>
<input class="form-input" v-model="formData.idType" placeholder="请输入证件类型" />
<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.number" placeholder="请输入证件编号" />
<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="showDatePicker = true">
<text :class="formData.expireDate ? '' : 'text-gray'">
{{ formData.expireDate || '请选择开始时间' }}
</text>
</view>
</view>
<!-- 结束日期 -->
<view class="form-item">
<view class="form-label">结束日期</view>
<view class="form-input form-select" @click="showDatePicker = true">
<text :class="formData.expireDate ? '' : 'text-gray'">
{{ formData.expireDate || '请选择结束时间' }}
<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.image">
<view class="upload-add" v-if="!formData.photoPreview">
<text class="upload-icon">+</text>
<text class="upload-text">上传照片</text>
</view>
<image v-else :src="formData.image" mode="aspectFill" class="upload-img"></image>
<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>
</view>
</scroll-view>
<view class="popup-footer">
<button class="btn-cancel" @click="showAddPopup = false">取消</button>
<button class="btn-confirm bg-blue" @click="handleSubmit">确定</button>
<button class="btn-cancel" @click="closePopup">取消</button>
<button class="btn-confirm bg-blue" @click="handleSubmit" :loading="submitting">确定</button>
</view>
</view>
</u-popup>
@@ -75,9 +123,11 @@
<!-- 日期选择器 -->
<u-datetime-picker
:show="showDatePicker"
v-model="datePickerValue"
mode="date"
@confirm="onDateConfirm"
@cancel="showDatePicker = false"
@cancel="onDateCancel"
@close="onDateCancel"
></u-datetime-picker>
<!-- 选择部门弹窗 -->
@@ -88,60 +138,289 @@
<view class="popup-close" @click="showDeptPopup = false">×</view>
</view>
<view class="dept-list">
<scroll-view class="dept-list" scroll-y v-if="deptList.length > 0">
<view
class="dept-item"
v-for="(item, index) in deptList"
:key="index"
v-for="item in deptList"
:key="item.id"
@click="selectedDept = item"
>
<view class="dept-checkbox" :class="{ 'dept-checkbox-active': selectedDept === item }">
<text v-if="selectedDept === item"></text>
<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 }}</text>
<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 } from 'vue';
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 hasData = ref(false);
// 证照列表
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 deptList = ref([
'湘西自治州和谐网络科技有限公司',
'湘西自治州和谐云大数据科技有限公司',
'湘西网络有限公司'
]);
const selectedDept = ref('');
// 编辑状态
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({
dept: '',
enterpriseId: '',
enterpriseName: '',
type: '',
idType: '',
number: '',
code: '',
startDate: '',
expireDate: '',
image: ''
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.dept = 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({
@@ -149,40 +428,102 @@ const chooseImage = () => {
sizeType: ['compressed'],
sourceType: ['album', 'camera'],
success: (res) => {
formData.image = res.tempFilePaths[0];
const tempFilePath = res.tempFilePaths[0];
formData.photoPreview = tempFilePath;
// 上传图片
uploadImage(tempFilePath);
}
});
};
// 日期选择确认
const onDateConfirm = (e) => {
const date = new Date(e.value);
const year = date.getFullYear();
const month = String(date.getMonth() + 1).padStart(2, '0');
const day = String(date.getDate()).padStart(2, '0');
formData.expireDate = `${year}-${month}-${day}`;
showDatePicker.value = false;
// 上传图片
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 = () => {
if (!formData.dept) {
const handleSubmit = async () => {
// 表单验证
if (!formData.enterpriseId) {
uni.showToast({ title: '请选择部门', icon: 'none' });
return;
}
console.log('提交数据:', formData);
uni.showToast({ title: '新增成功', icon: 'success' });
showAddPopup.value = false;
submitting.value = true;
// 重置表单
formData.dept = '';
formData.type = '';
formData.number = '';
formData.startDate = '';
formData.expireDate = '';
formData.image = '';
selectedDept.value = '';
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>
@@ -190,6 +531,96 @@ const handleSubmit = () => {
.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;
}
// 弹出框样式
@@ -257,6 +688,7 @@ const handleSubmit = () => {
display: flex;
align-items: center;
justify-content: center;
position: relative;
}
.upload-add {
@@ -276,12 +708,33 @@ const handleSubmit = () => {
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;