添加考生
Showing
10 changed files
with
487 additions
and
137 deletions
| ... | @@ -705,6 +705,15 @@ export function editLevel(data) { | ... | @@ -705,6 +705,15 @@ export function editLevel(data) { |
| 705 | }) | 705 | }) |
| 706 | } | 706 | } |
| 707 | 707 | ||
| 708 | // 添加考生(考级) | ||
| 709 | export function addPerson(data) { | ||
| 710 | return request({ | ||
| 711 | url: '/exam/person', | ||
| 712 | method: 'post', | ||
| 713 | params: data | ||
| 714 | }) | ||
| 715 | } | ||
| 716 | |||
| 708 | export function getVerityList(params) { | 717 | export function getVerityList(params) { |
| 709 | return request({ | 718 | return request({ |
| 710 | url: '/exam/info/verityList', | 719 | url: '/exam/info/verityList', |
| ... | @@ -2173,3 +2182,11 @@ export function getSmsCode(data) { | ... | @@ -2173,3 +2182,11 @@ export function getSmsCode(data) { |
| 2173 | params: data | 2182 | params: data |
| 2174 | }) | 2183 | }) |
| 2175 | } | 2184 | } |
| 2185 | |||
| 2186 | export function inMyMember(params) { | ||
| 2187 | return request({ | ||
| 2188 | url: `/person/info/inMyMember/`, | ||
| 2189 | method: 'get', | ||
| 2190 | params | ||
| 2191 | }) | ||
| 2192 | } | ... | ... |
| ... | @@ -15,13 +15,13 @@ | ... | @@ -15,13 +15,13 @@ |
| 15 | </uni-list-item> | 15 | </uni-list-item> |
| 16 | <uni-list-item title="会员编号" v-if="form.menCode" :rightText="form.menCode" /> | 16 | <uni-list-item title="会员编号" v-if="form.menCode" :rightText="form.menCode" /> |
| 17 | <uni-list-item title="机构名称" :rightText="form.name" /> | 17 | <uni-list-item title="机构名称" :rightText="form.name" /> |
| 18 | <uni-list-item title="所属省份"> | 18 | <!-- <uni-list-item title="所属省份"> |
| 19 | <template v-slot:footer> | 19 | <template v-slot:footer> |
| 20 | <uni-data-select :clear="false" disabled | 20 | <uni-data-select :clear="false" disabled |
| 21 | v-model="form.belongProvinceId" :localdata="regionsList"> | 21 | v-model="form.belongProvinceId" :localdata="regionsList"> |
| 22 | </uni-data-select> | 22 | </uni-data-select> |
| 23 | </template> | 23 | </template> |
| 24 | </uni-list-item> | 24 | </uni-list-item> --> |
| 25 | <uni-list-item title="社会信用代码" :rightText="form.creditCode" /> | 25 | <uni-list-item title="社会信用代码" :rightText="form.creditCode" /> |
| 26 | <uni-list-item v-if="isR" title="联系人" :rightText="form.certSiteContact" /> | 26 | <uni-list-item v-if="isR" title="联系人" :rightText="form.certSiteContact" /> |
| 27 | <uni-list-item v-else title="联系人" :rightText="form.siteContact" /> | 27 | <uni-list-item v-else title="联系人" :rightText="form.siteContact" /> | ... | ... |
| ... | @@ -73,10 +73,22 @@ | ... | @@ -73,10 +73,22 @@ |
| 73 | </view> | 73 | </view> |
| 74 | 74 | ||
| 75 | <!-- 操作栏(红框顶部统计+添加按钮) --> | 75 | <!-- 操作栏(红框顶部统计+添加按钮) --> |
| 76 | <button class="btn-add-student" @click="goChooseStudent"> | 76 | <view class="action-bar flex f-j-s"> |
| 77 | <uni-icons color="#fff" size="16" type="plus"></uni-icons> | 77 | <view class="btn-group"> |
| 78 | 添加考生 | 78 | |
| 79 | </button> | 79 | <button class="btn-add-student btn-outline" @click="goChooseStudent"> |
| 80 | 在线选择 | ||
| 81 | </button> | ||
| 82 | |||
| 83 | </view> | ||
| 84 | <view > | ||
| 85 | <button class="btn-add-student" @click="handleAdd"> | ||
| 86 | <uni-icons color="#fff" size="18" type="plus"></uni-icons> | ||
| 87 | 添加 | ||
| 88 | </button> | ||
| 89 | <!-- <uni-icons color="#faad14" size="18" type="warning"></uni-icons> 支持添加外部人员 --> | ||
| 90 | </view> | ||
| 91 | </view> | ||
| 80 | <view class="action-bar"> | 92 | <view class="action-bar"> |
| 81 | <view class="stat-info"> | 93 | <view class="stat-info"> |
| 82 | <text class="stat-total">共 {{ tablePersonInfo.total || 0 }} 人</text> | 94 | <text class="stat-total">共 {{ tablePersonInfo.total || 0 }} 人</text> |
| ... | @@ -86,7 +98,6 @@ | ... | @@ -86,7 +98,6 @@ |
| 86 | </view> | 98 | </view> |
| 87 | </view> | 99 | </view> |
| 88 | </view> | 100 | </view> |
| 89 | |||
| 90 | </view> | 101 | </view> |
| 91 | 102 | ||
| 92 | <!-- 考生列表(红框主体) --> | 103 | <!-- 考生列表(红框主体) --> |
| ... | @@ -154,7 +165,40 @@ | ... | @@ -154,7 +165,40 @@ |
| 154 | <button class="btn-red-kx" style="width: 25%;" @click="submitForm2(0)">保存</button> | 165 | <button class="btn-red-kx" style="width: 25%;" @click="submitForm2(0)">保存</button> |
| 155 | <button class="btn-red" style="width: 30%;" @click="submitForm2(1)">提交审核</button> | 166 | <button class="btn-red" style="width: 30%;" @click="submitForm2(1)">提交审核</button> |
| 156 | </view> | 167 | </view> |
| 157 | 168 | ||
| 169 | <!-- 添加考生弹框 --> | ||
| 170 | <uni-popup ref="addPopup" type="center" :mask-click="false" style="z-index: 99999"> | ||
| 171 | <view class="add-popup"> | ||
| 172 | <view class="popup-title">添加考生</view> | ||
| 173 | <view class="popup-content"> | ||
| 174 | <!-- <view class="form-item"> | ||
| 175 | <view class="form-label">姓名</view> | ||
| 176 | <view class="form-input"> | ||
| 177 | <input v-model="addForm.name" placeholder="请输入姓名" placeholder-class="placeholder-class"/> | ||
| 178 | </view> | ||
| 179 | </view> --> | ||
| 180 | <view class="form-item"> | ||
| 181 | <view class="form-label">证件类型</view> | ||
| 182 | <view class="form-input"> | ||
| 183 | <picker :value="idcTypeIndex" :range="idcTypeList" range-key="text" @change="onIdcTypeChange"> | ||
| 184 | <view class="picker-value">{{ idcTypeList[idcTypeIndex]?.text || '请选择证件类型' }}</view> | ||
| 185 | </picker> | ||
| 186 | </view> | ||
| 187 | </view> | ||
| 188 | <view class="form-item"> | ||
| 189 | <view class="form-label">证件号</view> | ||
| 190 | <view class="form-input"> | ||
| 191 | <input v-model="addForm.idcCode" placeholder="请输入证件号" placeholder-class="placeholder-class"/> | ||
| 192 | </view> | ||
| 193 | </view> | ||
| 194 | </view> | ||
| 195 | <view class="popup-btns"> | ||
| 196 | <view class="popup-btn cancel" @click="closeAddPopup">取消</view> | ||
| 197 | <view class="popup-btn confirm" @click="confirmAdd">确定</view> | ||
| 198 | </view> | ||
| 199 | </view> | ||
| 200 | </uni-popup> | ||
| 201 | |||
| 158 | </view> | 202 | </view> |
| 159 | </template> | 203 | </template> |
| 160 | 204 | ||
| ... | @@ -220,6 +264,20 @@ const range = ref([{ | ... | @@ -220,6 +264,20 @@ const range = ref([{ |
| 220 | text: '否' | 264 | text: '否' |
| 221 | }]) | 265 | }]) |
| 222 | 266 | ||
| 267 | // 添加考生弹框相关 | ||
| 268 | const addPopup = ref(null) | ||
| 269 | const addForm = ref({ | ||
| 270 | name: '', | ||
| 271 | idcType: '0', | ||
| 272 | idcCode: '' | ||
| 273 | }) | ||
| 274 | const idcTypeList = ref([ | ||
| 275 | { value: '0', text: '身份证' }, | ||
| 276 | { value: '1', text: '护照' }, | ||
| 277 | { value: '2', text: '军官证' } | ||
| 278 | ]) | ||
| 279 | const idcTypeIndex = ref(0) | ||
| 280 | |||
| 223 | let examId | 281 | let examId |
| 224 | 282 | ||
| 225 | onLoad(option => { | 283 | onLoad(option => { |
| ... | @@ -254,6 +312,7 @@ function initData(option) { | ... | @@ -254,6 +312,7 @@ function initData(option) { |
| 254 | } | 312 | } |
| 255 | 313 | ||
| 256 | onShow(() => { | 314 | onShow(() => { |
| 315 | console.log('addApply onShow called, examId:', examId, 'form.examId:', form.value.examId) | ||
| 257 | uni.$on('chosen', updateData) | 316 | uni.$on('chosen', updateData) |
| 258 | const curExamId = examId || form.value.examId | 317 | const curExamId = examId || form.value.examId |
| 259 | if (curExamId) { | 318 | if (curExamId) { |
| ... | @@ -405,6 +464,90 @@ function goChooseStudent() { | ... | @@ -405,6 +464,90 @@ function goChooseStudent() { |
| 405 | }) | 464 | }) |
| 406 | } | 465 | } |
| 407 | 466 | ||
| 467 | // 打开添加弹框 | ||
| 468 | function handleAdd() { | ||
| 469 | addForm.value = { | ||
| 470 | name: '', | ||
| 471 | idcType: '0', | ||
| 472 | idcCode: '' | ||
| 473 | } | ||
| 474 | idcTypeIndex.value = 0 | ||
| 475 | addPopup.value?.open() | ||
| 476 | } | ||
| 477 | |||
| 478 | // 关闭添加弹框 | ||
| 479 | function closeAddPopup() { | ||
| 480 | addPopup.value?.close() | ||
| 481 | } | ||
| 482 | |||
| 483 | // 证件类型选择 | ||
| 484 | function onIdcTypeChange(e) { | ||
| 485 | idcTypeIndex.value = e.detail.value | ||
| 486 | addForm.value.idcType = idcTypeList.value[idcTypeIndex.value].value | ||
| 487 | } | ||
| 488 | |||
| 489 | // 确认添加考生 | ||
| 490 | async function confirmAdd() { | ||
| 491 | if (!addForm.value.idcCode) { | ||
| 492 | uni.showToast({ title: '请输入证件号', icon: 'none' }) | ||
| 493 | return | ||
| 494 | } | ||
| 495 | |||
| 496 | uni.showLoading({ title: '校验中...', mask: true }) | ||
| 497 | |||
| 498 | try { | ||
| 499 | const checkRes = await api.inMyMember({ idcCode: addForm.value.idcCode }) | ||
| 500 | uni.hideLoading() | ||
| 501 | |||
| 502 | if (checkRes.data) { | ||
| 503 | // 人员已存在,直接添加 | ||
| 504 | await handelAddPerson() | ||
| 505 | } else { | ||
| 506 | // 人员不在本机构,弹出确认框 | ||
| 507 | uni.showModal({ | ||
| 508 | title: '系统提示', | ||
| 509 | content: '该人员已在其他机构登记,是否申请调入?如仅办理业务,请前往业务页面,点击【添加】直接办理。', | ||
| 510 | confirmText: '添加', | ||
| 511 | cancelText: '调动', | ||
| 512 | success: async function (res) { | ||
| 513 | if (res.confirm) { | ||
| 514 | await handelAddPerson() | ||
| 515 | } else if (res.cancel) { | ||
| 516 | // 跳转调动页面 | ||
| 517 | uni.navigateTo({ | ||
| 518 | url: '/personal/memberTransfer' | ||
| 519 | }) | ||
| 520 | } | ||
| 521 | } | ||
| 522 | }) | ||
| 523 | } | ||
| 524 | } catch (err) { | ||
| 525 | uni.hideLoading() | ||
| 526 | console.log(err) | ||
| 527 | } | ||
| 528 | } | ||
| 529 | |||
| 530 | // 执行添加考生 | ||
| 531 | async function handelAddPerson() { | ||
| 532 | uni.showLoading({ title: '添加中...', mask: true }) | ||
| 533 | try { | ||
| 534 | // 调用 /exam/person 接口添加考生 | ||
| 535 | await api.addPerson({ | ||
| 536 | examId: form.value.examId, | ||
| 537 | idcCode: addForm.value.idcCode, | ||
| 538 | idcType: addForm.value.idcType, | ||
| 539 | name: addForm.value.name || '' | ||
| 540 | }) | ||
| 541 | uni.hideLoading() | ||
| 542 | uni.showToast({ title: '添加成功', icon: 'success' }) | ||
| 543 | closeAddPopup() | ||
| 544 | getChosedStudentList() | ||
| 545 | } catch (err) { | ||
| 546 | uni.hideLoading() | ||
| 547 | console.log(err) | ||
| 548 | } | ||
| 549 | } | ||
| 550 | |||
| 408 | // 格式化日期时间 | 551 | // 格式化日期时间 |
| 409 | function formatDateTime(dateStr) { | 552 | function formatDateTime(dateStr) { |
| 410 | if (!dateStr) return '-' | 553 | if (!dateStr) return '-' |
| ... | @@ -781,19 +924,46 @@ function handleDelete(row) { | ... | @@ -781,19 +924,46 @@ function handleDelete(row) { |
| 781 | display: flex; | 924 | display: flex; |
| 782 | align-items: center; | 925 | align-items: center; |
| 783 | justify-content: center; | 926 | justify-content: center; |
| 784 | padding: 0 30rpx; | 927 | padding: 0 40rpx; |
| 785 | height: 64rpx; | 928 | height: 64rpx; |
| 786 | background: linear-gradient(135deg, #AD181F 0%, #c42a2a 100%); | 929 | background: linear-gradient(135deg, #AD181F 0%, #c42a2a 100%); |
| 787 | border-radius: 32rpx; | 930 | border-radius: 32rpx; |
| 788 | font-size: 26rpx; | 931 | font-size: 26rpx; |
| 789 | color: #fff; | 932 | color: #fff; |
| 790 | box-shadow: 0 4rpx 16rpx rgba(173, 24, 31, 0.3); | 933 | box-shadow: 0 4rpx 16rpx rgba(173, 24, 31, 0.3); |
| 934 | |||
| 935 | &.btn-outline { | ||
| 936 | background: #fff; | ||
| 937 | color: #AD181F; | ||
| 938 | border: 2rpx solid #AD181F; | ||
| 939 | box-shadow: none; | ||
| 940 | margin-left: 20rpx; | ||
| 941 | } | ||
| 942 | } | ||
| 943 | |||
| 944 | .btn-group { | ||
| 945 | display: flex; | ||
| 946 | align-items: center; | ||
| 947 | } | ||
| 948 | |||
| 949 | .hint-text { | ||
| 950 | font-size: 24rpx; | ||
| 951 | color: #faad14; | ||
| 952 | margin-top: 16rpx; | ||
| 953 | display: flex; | ||
| 954 | align-items: center; | ||
| 955 | |||
| 956 | |||
| 791 | } | 957 | } |
| 792 | 958 | ||
| 793 | /* 考生列表(核心优化) */ | 959 | /* 考生列表(核心优化) */ |
| 794 | .student-list { | 960 | .student-list { |
| 961 | position: relative; | ||
| 962 | z-index: 1; | ||
| 963 | |||
| 795 | .student-card { | 964 | .student-card { |
| 796 | position: relative; | 965 | position: relative; |
| 966 | z-index: 1; | ||
| 797 | // display: flex; | 967 | // display: flex; |
| 798 | 968 | ||
| 799 | // align-items: center; | 969 | // align-items: center; |
| ... | @@ -863,6 +1033,8 @@ function handleDelete(row) { | ... | @@ -863,6 +1033,8 @@ function handleDelete(row) { |
| 863 | margin-top: 20rpx; | 1033 | margin-top: 20rpx; |
| 864 | margin-left: 100rpx; | 1034 | margin-left: 100rpx; |
| 865 | height: 100rpx; | 1035 | height: 100rpx; |
| 1036 | position: relative; | ||
| 1037 | z-index: 1; | ||
| 866 | // flex-direction: column; | 1038 | // flex-direction: column; |
| 867 | // align-items: flex-end; | 1039 | // align-items: flex-end; |
| 868 | // gap: 16rpx; | 1040 | // gap: 16rpx; |
| ... | @@ -887,13 +1059,7 @@ function handleDelete(row) { | ... | @@ -887,13 +1059,7 @@ function handleDelete(row) { |
| 887 | .select-wrapper { | 1059 | .select-wrapper { |
| 888 | width: 160rpx; | 1060 | width: 160rpx; |
| 889 | position: relative; | 1061 | position: relative; |
| 890 | z-index: 99; | 1062 | z-index: 1; |
| 891 | } | ||
| 892 | |||
| 893 | .exam-level-select { | ||
| 894 | position: relative; | ||
| 895 | z-index: 999; | ||
| 896 | margin-bottom: 300rpx; | ||
| 897 | } | 1063 | } |
| 898 | } | 1064 | } |
| 899 | } | 1065 | } |
| ... | @@ -990,4 +1156,88 @@ function handleDelete(row) { | ... | @@ -990,4 +1156,88 @@ function handleDelete(row) { |
| 990 | font-weight: 600; | 1156 | font-weight: 600; |
| 991 | } | 1157 | } |
| 992 | } | 1158 | } |
| 1159 | |||
| 1160 | /* 添加考生弹框 */ | ||
| 1161 | .add-popup { | ||
| 1162 | width: 600rpx; | ||
| 1163 | background: #ffffff; | ||
| 1164 | border-radius: 24rpx; | ||
| 1165 | overflow: hidden; | ||
| 1166 | position: relative; | ||
| 1167 | z-index: 9999; | ||
| 1168 | } | ||
| 1169 | |||
| 1170 | .popup-title { | ||
| 1171 | font-size: 32rpx; | ||
| 1172 | font-weight: 500; | ||
| 1173 | color: #333; | ||
| 1174 | text-align: center; | ||
| 1175 | padding: 40rpx 30rpx 20rpx; | ||
| 1176 | } | ||
| 1177 | |||
| 1178 | .popup-content { | ||
| 1179 | padding: 20rpx 30rpx 40rpx; | ||
| 1180 | } | ||
| 1181 | |||
| 1182 | .form-item { | ||
| 1183 | display: flex; | ||
| 1184 | align-items: center; | ||
| 1185 | margin-bottom: 24rpx; | ||
| 1186 | } | ||
| 1187 | |||
| 1188 | .form-item:last-child { | ||
| 1189 | margin-bottom: 0; | ||
| 1190 | } | ||
| 1191 | |||
| 1192 | .form-label { | ||
| 1193 | width: 120rpx; | ||
| 1194 | font-size: 28rpx; | ||
| 1195 | color: #333; | ||
| 1196 | flex-shrink: 0; | ||
| 1197 | } | ||
| 1198 | |||
| 1199 | .form-input { | ||
| 1200 | flex: 1; | ||
| 1201 | background: #f5f5f5; | ||
| 1202 | border-radius: 12rpx; | ||
| 1203 | padding: 20rpx 24rpx; | ||
| 1204 | } | ||
| 1205 | |||
| 1206 | .form-input input { | ||
| 1207 | font-size: 28rpx; | ||
| 1208 | color: #333; | ||
| 1209 | width: 100%; | ||
| 1210 | } | ||
| 1211 | |||
| 1212 | .placeholder-class { | ||
| 1213 | color: #999; | ||
| 1214 | } | ||
| 1215 | |||
| 1216 | .picker-value { | ||
| 1217 | font-size: 28rpx; | ||
| 1218 | color: #333; | ||
| 1219 | } | ||
| 1220 | |||
| 1221 | .popup-btns { | ||
| 1222 | display: flex; | ||
| 1223 | border-top: 1rpx solid #eee; | ||
| 1224 | } | ||
| 1225 | |||
| 1226 | .popup-btn { | ||
| 1227 | flex: 1; | ||
| 1228 | height: 100rpx; | ||
| 1229 | line-height: 100rpx; | ||
| 1230 | text-align: center; | ||
| 1231 | font-size: 30rpx; | ||
| 1232 | } | ||
| 1233 | |||
| 1234 | .popup-btn.cancel { | ||
| 1235 | color: #666; | ||
| 1236 | border-right: 1rpx solid #eee; | ||
| 1237 | } | ||
| 1238 | |||
| 1239 | .popup-btn.confirm { | ||
| 1240 | color: #C4121B; | ||
| 1241 | font-weight: 500; | ||
| 1242 | } | ||
| 993 | </style> | 1243 | </style> | ... | ... |
| ... | @@ -45,7 +45,7 @@ | ... | @@ -45,7 +45,7 @@ |
| 45 | </view> | 45 | </view> |
| 46 | <view class="info-row" v-if="form.fileUrl"> | 46 | <view class="info-row" v-if="form.fileUrl"> |
| 47 | <text class="label">发票</text> | 47 | <text class="label">发票</text> |
| 48 | <text class="value text-primary" @click="downloadInvoice">下载发票</text> | 48 | <text class="value text-primary" @click="downloadInvoice">查看发票</text> |
| 49 | </view> | 49 | </view> |
| 50 | </view> | 50 | </view> |
| 51 | </view> | 51 | </view> |
| ... | @@ -190,18 +190,58 @@ function downloadInvoice() { | ... | @@ -190,18 +190,58 @@ function downloadInvoice() { |
| 190 | try { | 190 | try { |
| 191 | const invoice = JSON.parse(form.value.fileUrl) | 191 | const invoice = JSON.parse(form.value.fileUrl) |
| 192 | if (invoice && invoice[0]?.url) { | 192 | if (invoice && invoice[0]?.url) { |
| 193 | let fileUrl = invoice[0].url | 193 | let url = invoice[0].url |
| 194 | if (!fileUrl.startsWith('http')) { | 194 | if (!url.startsWith('http')) { |
| 195 | fileUrl = config.baseUrl_api + fileUrl | 195 | url = config.baseUrl_api + url |
| 196 | } | 196 | } |
| 197 | uni.previewImage({ | 197 | // 从 URL 中获取文件名判断类型 |
| 198 | urls: [fileUrl], | 198 | let ext = '' |
| 199 | success: () => { | 199 | const urlParts = url.split('/') |
| 200 | console.log('previewImage success') | 200 | const fileNameFromUrl = urlParts[urlParts.length - 1] || '' |
| 201 | if (fileNameFromUrl) { | ||
| 202 | const nameParts = fileNameFromUrl.split('.') | ||
| 203 | if (nameParts.length > 1) { | ||
| 204 | ext = nameParts[nameParts.length - 1].toLowerCase() | ||
| 205 | } | ||
| 206 | } | ||
| 207 | const isImage = ['jpg', 'jpeg', 'png', 'gif', 'bmp', 'webp'].includes(ext) | ||
| 208 | |||
| 209 | uni.showLoading({ title: '加载中' }) | ||
| 210 | uni.downloadFile({ | ||
| 211 | url: url, | ||
| 212 | success: (res) => { | ||
| 213 | uni.hideLoading() | ||
| 214 | if (res.statusCode === 200) { | ||
| 215 | if (isImage) { | ||
| 216 | // 图片预览 | ||
| 217 | uni.previewImage({ | ||
| 218 | urls: [res.tempFilePath] | ||
| 219 | }) | ||
| 220 | } else { | ||
| 221 | // 文件下载后打开 | ||
| 222 | uni.saveFile({ | ||
| 223 | tempFilePath: res.tempFilePath, | ||
| 224 | success: (saveRes) => { | ||
| 225 | uni.openDocument({ | ||
| 226 | filePath: saveRes.savedFilePath, | ||
| 227 | showMenu: true, | ||
| 228 | fail: () => { | ||
| 229 | uni.showToast({ title: '打开失败', icon: 'none' }) | ||
| 230 | } | ||
| 231 | }) | ||
| 232 | }, | ||
| 233 | fail: () => { | ||
| 234 | uni.showToast({ title: '保存失败', icon: 'none' }) | ||
| 235 | } | ||
| 236 | }) | ||
| 237 | } | ||
| 238 | } else { | ||
| 239 | uni.showToast({ title: '下载失败', icon: 'none' }) | ||
| 240 | } | ||
| 201 | }, | 241 | }, |
| 202 | fail: (err) => { | 242 | fail: () => { |
| 203 | console.error('previewImage fail:', err) | 243 | uni.hideLoading() |
| 204 | uni.showToast({ title: '打开图片失败', icon: 'none' }) | 244 | uni.showToast({ title: '下载失败', icon: 'none' }) |
| 205 | } | 245 | } |
| 206 | }) | 246 | }) |
| 207 | } | 247 | } | ... | ... |
| ... | @@ -54,18 +54,22 @@ | ... | @@ -54,18 +54,22 @@ |
| 54 | <view class="name mt0">{{ item.name || '-' }}</view> | 54 | <view class="name mt0">{{ item.name || '-' }}</view> |
| 55 | <view class="flexbox"> | 55 | <view class="flexbox"> |
| 56 | <view> | 56 | <view> |
| 57 | 结算单位 | ||
| 58 | <view>{{ item.memName || '-' }}</view> | ||
| 59 | </view> | ||
| 60 | <view> | ||
| 61 | 结算金额 | 57 | 结算金额 |
| 62 | <view class="text-red">¥{{ Number(item.price || 0).toFixed(2) }}</view> | 58 | <view class="text-red">¥{{ Number(item.price || 0).toFixed(2) }}</view> |
| 63 | </view> | 59 | </view> |
| 60 | <view> | ||
| 61 | 费用合计 | ||
| 62 | <view class="text-red">¥{{ Number(item.originPrice || 0).toFixed(2) }}</view> | ||
| 63 | </view> | ||
| 64 | |||
| 64 | </view> | 65 | </view> |
| 65 | <view class="flex f-j-s"> | 66 | <view class="flex f-j-s"> |
| 66 | <view class="info-time" v-if="item.commitTime"> | 67 | <view class="info-time" v-if="item.commitTime"> |
| 67 | 提交时间:{{ formatDate(item.commitTime) }} | 68 | 提交时间:{{ formatDate(item.commitTime) }} |
| 68 | </view> | 69 | </view> |
| 70 | <view class="info-time" v-if="item.auditTime"> | ||
| 71 | 审核时间:{{ formatDate(item.auditTime) }} | ||
| 72 | </view> | ||
| 69 | </view> | 73 | </view> |
| 70 | </view> | 74 | </view> |
| 71 | </view> | 75 | </view> |
| ... | @@ -202,7 +206,7 @@ function formatDate(dateStr) { | ... | @@ -202,7 +206,7 @@ function formatDate(dateStr) { |
| 202 | if (typeof dateStr === 'string' && dateStr.indexOf('T') > -1) { | 206 | if (typeof dateStr === 'string' && dateStr.indexOf('T') > -1) { |
| 203 | return dateStr.slice(0, 10) | 207 | return dateStr.slice(0, 10) |
| 204 | } | 208 | } |
| 205 | return dateStr | 209 | return dateStr.slice(0, 10) |
| 206 | } | 210 | } |
| 207 | 211 | ||
| 208 | function goDetail(item) { | 212 | function goDetail(item) { | ... | ... |
| ... | @@ -18,18 +18,24 @@ | ... | @@ -18,18 +18,24 @@ |
| 18 | </view> | 18 | </view> |
| 19 | 19 | ||
| 20 | <view class="appList" v-else> | 20 | <view class="appList" v-else> |
| 21 | <view class="appItem" v-for="(item, index) in list" :key="item.payId || index" @click="toggleSelect(item)"> | 21 | <view class="appItem" v-for="(item, index) in list" :key="item.payId || index"> |
| 22 | <view class="select-indicator" :class="{ selected: isSelected(item) }"> | ||
| 23 | <uni-icons v-if="isSelected(item)" type="checkmark" size="14" color="#fff"></uni-icons> | ||
| 24 | </view> | ||
| 25 | <view class="item-content"> | 22 | <view class="item-content"> |
| 26 | <view class="status"> | 23 | <view class="item-top"> |
| 27 | <text :class="getStatusClass(item.verityStatus)"> | 24 | <checkbox-group @change="onCheckboxChange(item.payId)" class="inline-checkbox"> |
| 28 | {{ item.verityStatusStr || '审核中' }} | 25 | <label> |
| 29 | </text> | 26 | <checkbox :value="item.payId" :checked="isSelected(item.payId)" color="#C4121B" /> |
| 30 | </view> | 27 | </label> |
| 31 | <view class="date"> | 28 | </checkbox-group> |
| 32 | <view class="text-primary" v-if="item.payCode">{{ item.payCode }}</view> | 29 | <view class="paycode-wrap"> |
| 30 | <view class="date1"> | ||
| 31 | <view class="text-primary" v-if="item.payCode">{{ item.payCode }}</view> | ||
| 32 | </view> | ||
| 33 | <view class="status"> | ||
| 34 | <text :class="getStatusClass(item.verityStatus)"> | ||
| 35 | {{ item.verityStatusStr || '审核中' }} | ||
| 36 | </text> | ||
| 37 | </view> | ||
| 38 | </view> | ||
| 33 | </view> | 39 | </view> |
| 34 | 40 | ||
| 35 | <view class="name mt0">{{ item.name || '-' }}</view> | 41 | <view class="name mt0">{{ item.name || '-' }}</view> |
| ... | @@ -174,18 +180,17 @@ function formatDate(dateStr) { | ... | @@ -174,18 +180,17 @@ function formatDate(dateStr) { |
| 174 | return dateStr | 180 | return dateStr |
| 175 | } | 181 | } |
| 176 | 182 | ||
| 177 | function toggleSelect(item) { | 183 | function onCheckboxChange(payId) { |
| 178 | if (selectedIds.value.has(item.payId)) { | 184 | if (selectedIds.value.has(payId)) { |
| 179 | selectedIds.value.delete(item.payId) | 185 | selectedIds.value.delete(payId) |
| 180 | } else { | 186 | } else { |
| 181 | selectedIds.value.add(item.payId) | 187 | selectedIds.value.add(payId) |
| 182 | } | 188 | } |
| 183 | selectedIds.value = new Set(selectedIds.value) | 189 | selectedIds.value = new Set(selectedIds.value) |
| 184 | } | 190 | } |
| 185 | 191 | ||
| 186 | // 修复:这里传 item 而不是 payId | 192 | function isSelected(payId) { |
| 187 | function isSelected(item) { | 193 | return selectedIds.value.has(payId) |
| 188 | return selectedIds.value.has(item.payId) | ||
| 189 | } | 194 | } |
| 190 | 195 | ||
| 191 | function handleSettlement() { | 196 | function handleSettlement() { |
| ... | @@ -227,60 +232,58 @@ function handleSettlement() { | ... | @@ -227,60 +232,58 @@ function handleSettlement() { |
| 227 | padding: 30rpx; | 232 | padding: 30rpx; |
| 228 | margin-bottom: 20rpx; | 233 | margin-bottom: 20rpx; |
| 229 | box-shadow: 0 4rpx 20rpx rgba(0, 0, 0, 0.05); | 234 | box-shadow: 0 4rpx 20rpx rgba(0, 0, 0, 0.05); |
| 230 | display: flex; | ||
| 231 | align-items: center; | ||
| 232 | position: relative; | 235 | position: relative; |
| 233 | 236 | ||
| 234 | // 选择框 - 修复样式 | ||
| 235 | .select-indicator { | ||
| 236 | width: 36rpx; | ||
| 237 | height: 36rpx; | ||
| 238 | border-radius: 50%; | ||
| 239 | border: 2rpx solid #ddd; | ||
| 240 | display: flex; | ||
| 241 | align-items: center; | ||
| 242 | justify-content: center; | ||
| 243 | margin-right: 20rpx; | ||
| 244 | flex-shrink: 0; | ||
| 245 | transition: all 0.2s; | ||
| 246 | |||
| 247 | &.selected { | ||
| 248 | background-color: #AD181F; | ||
| 249 | border-color: #AD181F; | ||
| 250 | } | ||
| 251 | } | ||
| 252 | |||
| 253 | .item-content { | 237 | .item-content { |
| 254 | flex: 1; | 238 | flex: 1; |
| 255 | min-width: 0; | 239 | min-width: 0; |
| 256 | } | 240 | } |
| 257 | 241 | ||
| 258 | .status { | 242 | .item-top { |
| 259 | display: inline-block; | 243 | display: flex; |
| 260 | padding: 6rpx 20rpx; | 244 | align-items: center; |
| 261 | border-radius: 20rpx; | ||
| 262 | font-size: 24rpx; | ||
| 263 | margin-bottom: 16rpx; | 245 | margin-bottom: 16rpx; |
| 264 | 246 | border-bottom: 1px dashed #e5e5e5; | |
| 265 | .text-success { | 247 | .inline-checkbox { |
| 266 | color: #4caf50; | 248 | display: inline-flex; |
| 249 | margin-right: 10rpx; | ||
| 250 | width: 50rpx; | ||
| 251 | margin-bottom: 10rpx; | ||
| 252 | |||
| 253 | checkbox { | ||
| 254 | transform: scale(0.85); | ||
| 255 | } | ||
| 267 | } | 256 | } |
| 268 | .text-warning { | 257 | |
| 269 | color: #ff9800; | 258 | .paycode-wrap { |
| 259 | display: flex; | ||
| 260 | align-items: center; | ||
| 261 | flex: 1; | ||
| 270 | } | 262 | } |
| 271 | .text-danger { | 263 | |
| 272 | color: #f5222d; | 264 | .date1 { |
| 265 | display: inline-flex; | ||
| 266 | align-items: center; | ||
| 273 | } | 267 | } |
| 274 | } | ||
| 275 | 268 | ||
| 276 | .date { | 269 | .status { |
| 277 | font-size: 24rpx; | 270 | display: inline-block; |
| 278 | color: #999; | 271 | padding: 6rpx 20rpx; |
| 279 | } | 272 | border-radius: 20rpx; |
| 273 | font-size: 24rpx; | ||
| 274 | background: #f5f5f5; | ||
| 275 | margin-top: 10rpx; | ||
| 280 | 276 | ||
| 281 | .text-primary { | 277 | .text-success { |
| 282 | font-size: 28rpx; | 278 | color: #4caf50; |
| 283 | color: #AD181F; | 279 | } |
| 280 | .text-warning { | ||
| 281 | color: #ff9800; | ||
| 282 | } | ||
| 283 | .text-danger { | ||
| 284 | color: #f5222d; | ||
| 285 | } | ||
| 286 | } | ||
| 284 | } | 287 | } |
| 285 | 288 | ||
| 286 | .name { | 289 | .name { |
| ... | @@ -295,6 +298,11 @@ function handleSettlement() { | ... | @@ -295,6 +298,11 @@ function handleSettlement() { |
| 295 | } | 298 | } |
| 296 | } | 299 | } |
| 297 | 300 | ||
| 301 | .text-primary { | ||
| 302 | font-size: 28rpx; | ||
| 303 | color: #AD181F; | ||
| 304 | } | ||
| 305 | |||
| 298 | .flexbox { | 306 | .flexbox { |
| 299 | display: flex; | 307 | display: flex; |
| 300 | justify-content: space-between; | 308 | justify-content: space-between; | ... | ... |
| ... | @@ -85,8 +85,8 @@ onLoad((options) => { | ... | @@ -85,8 +85,8 @@ onLoad((options) => { |
| 85 | 85 | ||
| 86 | // 数字转汉字 | 86 | // 数字转汉字 |
| 87 | function szToHz(num) { | 87 | function szToHz(num) { |
| 88 | const arr = ['一', '二', '三', '四', '五', '六', '七', '八', '九', '十'] | 88 | const hzArr = ['〇', '一', '二', '三', '四', '五', '六', '七', '八', '九', '十'] |
| 89 | return arr[num] || num + 1 | 89 | return hzArr[parseInt(num)] |
| 90 | } | 90 | } |
| 91 | 91 | ||
| 92 | async function getConfirm(ids) { | 92 | async function getConfirm(ids) { |
| ... | @@ -213,7 +213,7 @@ async function handleSubmit() { | ... | @@ -213,7 +213,7 @@ async function handleSubmit() { |
| 213 | padding: 30rpx; | 213 | padding: 30rpx; |
| 214 | margin-bottom: 20rpx; | 214 | margin-bottom: 20rpx; |
| 215 | box-shadow: 0 4rpx 20rpx rgba(0, 0, 0, 0.05); | 215 | box-shadow: 0 4rpx 20rpx rgba(0, 0, 0, 0.05); |
| 216 | border-left: 8rpx solid #27a9e7; | 216 | // border-left: 8rpx solid #27a9e7; |
| 217 | 217 | ||
| 218 | .section-title { | 218 | .section-title { |
| 219 | font-size: 28rpx; | 219 | font-size: 28rpx; | ... | ... |
| ... | @@ -44,8 +44,8 @@ | ... | @@ -44,8 +44,8 @@ |
| 44 | <text class="value"> {{ form.auditTime }}</text> | 44 | <text class="value"> {{ form.auditTime }}</text> |
| 45 | </view> | 45 | </view> |
| 46 | <view class="info-item"> | 46 | <view class="info-item"> |
| 47 | <text class="label">下载发票</text> | 47 | <text class="label">发票</text> |
| 48 | <text class="value link" @click="handelInvoice(form.fileUrl)"> 下载发票</text> | 48 | <text class="value link" @click="handelInvoice(form.fileUrl)"> 查看发票</text> |
| 49 | </view> | 49 | </view> |
| 50 | </view> | 50 | </view> |
| 51 | </view> | 51 | </view> |
| ... | @@ -266,7 +266,6 @@ function getVerityStatusClass(status) { | ... | @@ -266,7 +266,6 @@ function getVerityStatusClass(status) { |
| 266 | } | 266 | } |
| 267 | 267 | ||
| 268 | function handelInvoice(fileUrl) { | 268 | function handelInvoice(fileUrl) { |
| 269 | console.log('fileUrl', fileUrl) | ||
| 270 | if (!fileUrl) { | 269 | if (!fileUrl) { |
| 271 | uni.showToast({ title: '暂无发票', icon: 'none' }) | 270 | uni.showToast({ title: '暂无发票', icon: 'none' }) |
| 272 | return | 271 | return |
| ... | @@ -274,61 +273,61 @@ function handelInvoice(fileUrl) { | ... | @@ -274,61 +273,61 @@ function handelInvoice(fileUrl) { |
| 274 | try { | 273 | try { |
| 275 | const invoice = JSON.parse(fileUrl) | 274 | const invoice = JSON.parse(fileUrl) |
| 276 | if (invoice && invoice.length > 0) { | 275 | if (invoice && invoice.length > 0) { |
| 277 | let url = invoice[0].url | 276 | let url = invoice[0].url || '' |
| 278 | const fileName = invoice[0].name || '' | 277 | if (!url) { |
| 279 | // 避免使用可选链操作符,确保兼容性 | 278 | uni.showToast({ title: '暂无发票', icon: 'none' }) |
| 280 | let ext = '' | 279 | return |
| 281 | if (fileName) { | ||
| 282 | const parts = fileName.split('.') | ||
| 283 | if (parts.length > 1) { | ||
| 284 | ext = parts[parts.length - 1].toLowerCase() | ||
| 285 | } | ||
| 286 | } | 280 | } |
| 287 | console.log('发票信息:', { url, fileName, ext }) | ||
| 288 | // 判断是否需要拼接 baseUrl | 281 | // 判断是否需要拼接 baseUrl |
| 289 | if (url.indexOf('http') === -1) { | 282 | if (url.indexOf('http') === -1) { |
| 290 | url = config.baseUrl_api + url | 283 | url = config.baseUrl_api + url |
| 291 | } | 284 | } |
| 292 | console.log('完整下载地址:', url) | 285 | // 从 URL 中获取文件名判断类型 |
| 293 | uni.showLoading({ title: '下载中' }) | 286 | let ext = '' |
| 287 | const urlParts = url.split('/') | ||
| 288 | const fileNameFromUrl = urlParts[urlParts.length - 1] || '' | ||
| 289 | if (fileNameFromUrl) { | ||
| 290 | const nameParts = fileNameFromUrl.split('.') | ||
| 291 | if (nameParts.length > 1) { | ||
| 292 | ext = nameParts[nameParts.length - 1].toLowerCase() | ||
| 293 | } | ||
| 294 | } | ||
| 295 | const isImage = ['jpg', 'jpeg', 'png', 'gif', 'bmp', 'webp'].includes(ext) | ||
| 296 | |||
| 297 | uni.showLoading({ title: '加载中' }) | ||
| 294 | uni.downloadFile({ | 298 | uni.downloadFile({ |
| 295 | url: url, | 299 | url: url, |
| 296 | success: (res) => { | 300 | success: (res) => { |
| 297 | console.log('下载成功:', res) | ||
| 298 | uni.hideLoading() | 301 | uni.hideLoading() |
| 299 | if (res.statusCode === 200) { | 302 | if (res.statusCode === 200) { |
| 300 | // 图片类型用 previewImage 预览 | 303 | if (isImage) { |
| 301 | if (['jpg', 'jpeg', 'png', 'gif', 'bmp', 'webp'].includes(ext)) { | 304 | // 图片预览 |
| 302 | uni.previewImage({ | 305 | uni.previewImage({ |
| 303 | urls: [res.tempFilePath], | 306 | urls: [res.tempFilePath] |
| 304 | success: () => { | ||
| 305 | console.log('预览成功') | ||
| 306 | }, | ||
| 307 | fail: (err) => { | ||
| 308 | console.error('预览失败:', err) | ||
| 309 | uni.showToast({ title: '预览失败', icon: 'none' }) | ||
| 310 | } | ||
| 311 | }) | 307 | }) |
| 312 | } else { | 308 | } else { |
| 313 | // PDF 等文档用 openDocument 打开 | 309 | // 文件下载后打开 |
| 314 | uni.openDocument({ | 310 | uni.saveFile({ |
| 315 | filePath: res.tempFilePath, | 311 | tempFilePath: res.tempFilePath, |
| 316 | showMenu: true, | 312 | success: (saveRes) => { |
| 317 | success: () => { | 313 | uni.openDocument({ |
| 318 | console.log('打开文档成功') | 314 | filePath: saveRes.savedFilePath, |
| 315 | showMenu: true, | ||
| 316 | fail: () => { | ||
| 317 | uni.showToast({ title: '打开失败', icon: 'none' }) | ||
| 318 | } | ||
| 319 | }) | ||
| 319 | }, | 320 | }, |
| 320 | fail: (err) => { | 321 | fail: () => { |
| 321 | console.error('打开失败:', err) | 322 | uni.showToast({ title: '保存失败', icon: 'none' }) |
| 322 | uni.showToast({ title: '打开失败', icon: 'none' }) | ||
| 323 | } | 323 | } |
| 324 | }) | 324 | }) |
| 325 | } | 325 | } |
| 326 | } else { | 326 | } else { |
| 327 | uni.showToast({ title: '下载失败: ' + res.statusCode, icon: 'none' }) | 327 | uni.showToast({ title: '下载失败', icon: 'none' }) |
| 328 | } | 328 | } |
| 329 | }, | 329 | }, |
| 330 | fail: (err) => { | 330 | fail: () => { |
| 331 | console.error('下载失败:', err) | ||
| 332 | uni.hideLoading() | 331 | uni.hideLoading() |
| 333 | uni.showToast({ title: '下载失败', icon: 'none' }) | 332 | uni.showToast({ title: '下载失败', icon: 'none' }) |
| 334 | } | 333 | } | ... | ... |
| ... | @@ -239,18 +239,31 @@ let hasOpenedBindPopup = false | ... | @@ -239,18 +239,31 @@ let hasOpenedBindPopup = false |
| 239 | 239 | ||
| 240 | onShow(() => { | 240 | onShow(() => { |
| 241 | let webUserName = uni.getStorageSync('webUserName') | 241 | let webUserName = uni.getStorageSync('webUserName') |
| 242 | console.log(webUserName) | ||
| 243 | if (!webUserName) { | 242 | if (!webUserName) { |
| 244 | wxLogin().then(getWebInfo) | 243 | // 登录后需要等待数据加载完成 |
| 244 | wxLogin().then(res => { | ||
| 245 | getWebInfo().then(() => { | ||
| 246 | // 数据加载完成后检查是否需要弹出绑定框 | ||
| 247 | checkAndOpenBindPopup() | ||
| 248 | }) | ||
| 249 | }) | ||
| 250 | } else { | ||
| 251 | // 已登录,直接检查 | ||
| 252 | checkAndOpenBindPopup() | ||
| 245 | } | 253 | } |
| 246 | // 只有当 perInfo 数据存在且 perCode 为空时才弹出 | 254 | }) |
| 247 | if (perInfo.value && !perInfo.value.perCode && !hasOpenedBindPopup) { | 255 | |
| 256 | // 检查是否需要弹出绑定框 | ||
| 257 | const checkAndOpenBindPopup = () => { | ||
| 258 | // 确保 userStore 数据已更新 | ||
| 259 | const currentPerInfo = userStore.perInfo | ||
| 260 | if (currentPerInfo && !currentPerInfo.perCode && !hasOpenedBindPopup) { | ||
| 248 | hasOpenedBindPopup = true | 261 | hasOpenedBindPopup = true |
| 249 | nextTick(() => { | 262 | nextTick(() => { |
| 250 | openBindPopup() | 263 | openBindPopup() |
| 251 | }) | 264 | }) |
| 252 | } | 265 | } |
| 253 | }) | 266 | } |
| 254 | 267 | ||
| 255 | 268 | ||
| 256 | // watch(() => perInfo.value, (newVal, oldVal) => { | 269 | // watch(() => perInfo.value, (newVal, oldVal) => { | ... | ... |
| ... | @@ -119,6 +119,10 @@ | ... | @@ -119,6 +119,10 @@ |
| 119 | <text class="more" @click.stop="goToDetail(item)">更多</text> | 119 | <text class="more" @click.stop="goToDetail(item)">更多</text> |
| 120 | </view> | 120 | </view> |
| 121 | <view class="btn-flex"> | 121 | <view class="btn-flex"> |
| 122 | <!-- 待缴费:去缴费 --> | ||
| 123 | <!-- <template v-if="item.payStatus == 0"> | ||
| 124 | <button class="btn btn-pay" @click.stop="goPay(item)">去缴费</button> | ||
| 125 | </template> --> | ||
| 122 | <button class="btn btn-info" @click.stop="goToDetail(item)">查看明细</button> | 126 | <button class="btn btn-info" @click.stop="goToDetail(item)">查看明细</button> |
| 123 | <!-- 已缴费:申请开票/已开票(需要审核通过才能开票) --> | 127 | <!-- 已缴费:申请开票/已开票(需要审核通过才能开票) --> |
| 124 | <template v-if="item.payStatus == 1 && item.invoiceStatus != 1 && item.auditStatus == 2 && item.price > 0"> | 128 | <template v-if="item.payStatus == 1 && item.invoiceStatus != 1 && item.auditStatus == 2 && item.price > 0"> |
| ... | @@ -368,6 +372,21 @@ const goToDetail = (item) => { | ... | @@ -368,6 +372,21 @@ const goToDetail = (item) => { |
| 368 | uni.navigateTo({url: `/personalVip/orderDetail?rangeId=${item.sourceId || item.id}&type=${queryParams.type}`}); | 372 | uni.navigateTo({url: `/personalVip/orderDetail?rangeId=${item.sourceId || item.id}&type=${queryParams.type}`}); |
| 369 | }; | 373 | }; |
| 370 | 374 | ||
| 375 | // 去缴费 | ||
| 376 | const goPay = (item) => { | ||
| 377 | const baseFormData = { | ||
| 378 | rangeId: item.sourceId || item.id, | ||
| 379 | payYear: item.content?.yearCount || 1, | ||
| 380 | sourceId: item.sourceId || item.id, | ||
| 381 | tradeNo: item.tradeNo, | ||
| 382 | price: item.price | ||
| 383 | }; | ||
| 384 | const formStr = encodeURIComponent(JSON.stringify(baseFormData)); | ||
| 385 | uni.navigateTo({ | ||
| 386 | url: `/personal/goPay_per?baseFormData=${formStr}` | ||
| 387 | }); | ||
| 388 | }; | ||
| 389 | |||
| 371 | // 删除订单 | 390 | // 删除订单 |
| 372 | const handleDelete = (item) => { | 391 | const handleDelete = (item) => { |
| 373 | currentOrder.value = item; | 392 | currentOrder.value = item; | ... | ... |
-
Please register or sign in to post a comment