843f28df by lttnew

个人会员中心+注册+bug

1 parent 8b3e35cc
...@@ -1714,6 +1714,14 @@ export function unbindUser() { ...@@ -1714,6 +1714,14 @@ export function unbindUser() {
1714 }) 1714 })
1715 } 1715 }
1716 1716
1717 // 电子会员证下载
1718 export function downStuCertSingle(pId) {
1719 return request({
1720 url: `/person/info/downStuCertSingle/${pId}`,
1721 method: 'post'
1722 })
1723 }
1724
1717 /** 1725 /**
1718 * 订单列表 1726 * 订单列表
1719 * @param params 1727 * @param params
...@@ -2028,3 +2036,45 @@ export function memBerAuditList(params) { ...@@ -2028,3 +2036,45 @@ export function memBerAuditList(params) {
2028 params: params 2036 params: params
2029 }) 2037 })
2030 } 2038 }
2039
2040 /**
2041 * 结算审核列表
2042 * @param params
2043 * @returns {*}
2044 */
2045 export function settlementList(params) {
2046 return request({
2047 url: '/exam/paymentSubmit/list',
2048 method: 'get',
2049 params: params
2050 })
2051 }
2052
2053 /**
2054 * 结算审核(通过/拒绝)
2055 * @param data { ids, type, reason }
2056 * @returns {*}
2057 */
2058 export function settlementAudit(data) {
2059 return request({
2060 url: `/exam/paymentSubmit/audit/${data.ids}`,
2061 method: 'post',
2062 params: {
2063 type: data.type,
2064 reason: data.reason
2065 }
2066 })
2067 }
2068
2069 /**
2070 * 结算详情列表(根据结算单ID获取关联的缴费单)
2071 * @param params { payIds, pageNum, pageSize }
2072 * @returns {*}
2073 */
2074 export function settlementDetailList(params) {
2075 return request({
2076 url: '/exam/payment/list',
2077 method: 'get',
2078 params: params
2079 })
2080 }
......
...@@ -120,7 +120,8 @@ function requestPaymentCredential(encodedData) { ...@@ -120,7 +120,8 @@ function requestPaymentCredential(encodedData) {
120 header: { 120 header: {
121 'Content-Type': 'application/x-www-form-urlencoded' 121 'Content-Type': 'application/x-www-form-urlencoded'
122 }, 122 },
123 data: encodedData 123 data: encodedData,
124 timeout: 60000 // 60秒超时,与业务请求保持一致
124 }) 125 })
125 } 126 }
126 127
......
...@@ -60,10 +60,13 @@ function handleTokenExpire() { ...@@ -60,10 +60,13 @@ function handleTokenExpire() {
60 60
61 // 显示错误提示 61 // 显示错误提示
62 function showError(msg) { 62 function showError(msg) {
63 console.log('showError called:', msg)
64 // 先隐藏可能存在的 loading,确保 Toast 能显示
65 uni.hideLoading()
63 uni.showToast({ 66 uni.showToast({
64 title: msg || '请求失败', 67 title: msg || '请求失败',
65 icon: 'none', 68 icon: 'none',
66 duration: 2000 69 duration: 3000
67 }) 70 })
68 } 71 }
69 72
...@@ -119,9 +122,16 @@ const request = function (req) { ...@@ -119,9 +122,16 @@ const request = function (req) {
119 return 122 return
120 } 123 }
121 124
122 // 其他业务错误 125 // 业务错误(code != 200 且非 Token 过期)- 统一显示错误提示
123 showError(data.msg || '请求失败') 126 const errorMsg = data.msg || '操作失败'
124 reject(new Error(data.msg || '请求失败')) 127 showError(errorMsg)
128
129 // code == 500 时仅显示提示,不抛出异常,避免页面 catch 覆盖错误信息
130 if (data.code == 500) {
131 return
132 }
133
134 reject(new Error(errorMsg))
125 135
126 }).catch(error => { 136 }).catch(error => {
127 console.error('请求失败:', error) 137 console.error('请求失败:', error)
...@@ -139,9 +149,12 @@ const request = function (req) { ...@@ -139,9 +149,12 @@ const request = function (req) {
139 149
140 reject(error) 150 reject(error)
141 }).finally(() => { 151 }).finally(() => {
152 // 延迟隐藏 loading,确保错误提示能显示
153 setTimeout(() => {
142 if (req.showLoading != false) { 154 if (req.showLoading != false) {
143 hideLoading() 155 hideLoading()
144 } 156 }
157 }, 100)
145 }) 158 })
146 }) 159 })
147 } 160 }
......
...@@ -13,15 +13,15 @@ ...@@ -13,15 +13,15 @@
13 <view class="vipData mt30" style="flex-wrap: wrap;padding: 20rpx;"> 13 <view class="vipData mt30" style="flex-wrap: wrap;padding: 20rpx;">
14 <view class="w50"> 14 <view class="w50">
15 年限合计: 15 年限合计:
16 <text>{{ form?.renewYear }}</text> 16 <text>{{ form?.renewYear }}</text>
17 </view> 17 </view>
18 <view class="w50"> 18 <view class="w50">
19 费用合计: 19 费用合计:
20 <text>{{ form?.allPrice }}</text> 20 <text>{{ form?.allPrice }}</text>
21 </view> 21 </view>
22 <view class="w50"> 22 <view class="w50">
23 政策优惠: 23 政策优惠:
24 <text>{{ form?.discount }}</text> 24 <text>{{ form?.discount }}</text>
25 </view> 25 </view>
26 <view class="w50"> 26 <view class="w50">
27 付款费用: 27 付款费用:
......
...@@ -117,7 +117,7 @@ ...@@ -117,7 +117,7 @@
117 </view> 117 </view>
118 <view class="level-item"> 118 <view class="level-item">
119 <text class="level-label">考试级别</text> 119 <text class="level-label">考试级别</text>
120 <view class="select-wrapper" @click="changeLevelfather(n)"> 120 <view class="select-wrapper exam-level-select" @click="changeLevelfather(n)">
121 <uni-data-select v-model="n.levelNew" :clear="false" :localdata="levelArr" @change="changeLevel"/> 121 <uni-data-select v-model="n.levelNew" :clear="false" :localdata="levelArr" @change="changeLevel"/>
122 </view> 122 </view>
123 </view> 123 </view>
...@@ -427,7 +427,10 @@ function getChosedStudentList() { ...@@ -427,7 +427,10 @@ function getChosedStudentList() {
427 d.levelRecommend = '9' 427 d.levelRecommend = '9'
428 } 428 }
429 429
430 if (!d.levelNew) { 430 // 原级别是一级时,levelNew 默认为空,不使用推荐值
431 if (d.levelOld === '1') {
432 d.levelNew = ''
433 } else if (!d.levelNew) {
431 d.levelNew = d.levelRecommend 434 d.levelNew = d.levelRecommend
432 } 435 }
433 436
...@@ -475,10 +478,21 @@ function szToHz(num) { ...@@ -475,10 +478,21 @@ function szToHz(num) {
475 478
476 let nowRow 479 let nowRow
477 480
478 function changeLevelfather(row) { 481 function changeLevelfather(row, flag = 0) {
479 nowRow = row 482 const data = _.map(infoList.value, (d) => {
480 api.jiDropDownBox({ 483 return {
481 perId: row.perId 484 id: d.id,
485 levelNew: d.levelNew,
486 // score: d.score,
487 isPass: d.isPass
488 }
489 })
490 api.editLevel({
491 examId: form.value.examId,
492 personInfo: JSON.stringify(data),
493 transcript: form.value.transcript,
494 // perId: row.perId,
495 status: flag
482 }).then(res => { 496 }).then(res => {
483 levelArr.value = res.data 497 levelArr.value = res.data
484 for (let l of levelArr.value) { 498 for (let l of levelArr.value) {
...@@ -489,36 +503,43 @@ function changeLevelfather(row) { ...@@ -489,36 +503,43 @@ function changeLevelfather(row) {
489 } 503 }
490 504
491 function changeLevel(e) { 505 function changeLevel(e) {
492 if (e == nowRow.levelOld) { 506 // 切换考试级别时弹出确认框
493 uni.showToast({title: '考试级别重复,请重新选择!', icon: 'none'})
494 nowRow.levelNew = nowRow.levelRecommend
495 return
496 }
497 if (e !== nowRow.levelRecommend) {
498 uni.showModal({ 507 uni.showModal({
499 title: '提示', 508 title: '提示',
500 content: `建议考试级别为 "${szToHz(nowRow.levelRecommend)}级" ,确定要修改为${szToHz(e)}级吗?`, 509 content: '请仔细核实本次等级申报是否正确!',
501 success: function (res) { 510 success: function (res) {
502 if (res.confirm) { 511 if (res.confirm) {
512 // 保存当前行数据
513 const data = _.map(infoList.value, (d) => {
514 return {
515 id: d.id,
516 levelNew: d.levelNew,
517 isPass: d.isPass
518 }
519 })
520 api.editLevel({
521 examId: form.value.examId,
522 personInfo: JSON.stringify(data),
523 transcript: form.value.transcript,
524 status: 0
525 }).then(() => {
526 // 保存成功后更新统计
503 getTablePersonInfo() 527 getTablePersonInfo()
528 })
504 } else { 529 } else {
505 nowRow.levelNew = nowRow.levelRecommend 530 // 取消时恢复为推荐级别
531 nowRow.levelNew = nowRow.levelRecommend != 0 ? nowRow.levelRecommend : ''
506 } 532 }
507 }, 533 },
508 fail: function (res) { 534 fail: function (res) {
509 nowRow.levelNew = nowRow.levelRecommend 535 nowRow.levelNew = nowRow.levelRecommend != 0 ? nowRow.levelRecommend : ''
510 } 536 }
511 }) 537 })
512 }
513 } 538 }
514 539
515 function submitForm2(flag) { 540 function submitForm2(flag) {
516 // 循环校验考试级别 541 // 循环校验考试级别是否选择(考试级别重复可以提交)
517 for (let item of infoList.value) { 542 for (let item of infoList.value) {
518 if (item.levelNew == item.levelOld) {
519 uni.showToast({title: `${item.realName}考试级别重复,请重新选择!`, icon: 'none'})
520 return
521 }
522 if (!item.levelNew) { 543 if (!item.levelNew) {
523 uni.showToast({title: `${item.realName}请选择考试级别!`, icon: 'none'}) 544 uni.showToast({title: `${item.realName}请选择考试级别!`, icon: 'none'})
524 return 545 return
...@@ -536,16 +557,11 @@ function submitForm2(flag) { ...@@ -536,16 +557,11 @@ function submitForm2(flag) {
536 content: `请确认人员照片是否已更新?`, 557 content: `请确认人员照片是否已更新?`,
537 success: function (res) { 558 success: function (res) {
538 if (res.confirm) { 559 if (res.confirm) {
539 // saveStep2(flag).then(() => { 560 saveStep2(flag).then(() => {
540 // uni.showToast({title: '提交成功', icon: 'none'})
541 // uni.navigateTo({
542 // url: `/level/paymentDetail?examId=${form.value.examId}`
543 // })
544 // })
545
546 uni.navigateTo({ 561 uni.navigateTo({
547 url: `/level/paymentDetail?examId=${form.value.examId}` 562 url: `/level/paymentDetail?examId=${form.value.examId}`
548 }) 563 })
564 })
549 } 565 }
550 } 566 }
551 }) 567 })
...@@ -866,7 +882,15 @@ function handleDelete(row) { ...@@ -866,7 +882,15 @@ function handleDelete(row) {
866 } 882 }
867 883
868 .select-wrapper { 884 .select-wrapper {
869 width: 120rpx; 885 width: 160rpx;
886 position: relative;
887 z-index: 99;
888 }
889
890 .exam-level-select {
891 position: relative;
892 z-index: 999;
893 margin-bottom: 300rpx;
870 } 894 }
871 } 895 }
872 } 896 }
......
...@@ -23,9 +23,10 @@ ...@@ -23,9 +23,10 @@
23 <view class="date">注册地:{{n.memName||'-'}}</view> 23 <view class="date">注册地:{{n.memName||'-'}}</view>
24 </view> 24 </view>
25 <view class="status"> 25 <view class="status">
26 <text v-if="isChosen(n)" class="text-gray">已选</text> 26 <text v-if="isChosen(n)" class="text-chosen">已选</text>
27 <!-- <text v-else-if="n.canChoose != 1" class="text-gray">不可选</text> --> 27 <!-- <text v-else-if="n.canChoose != 1" class="text-gray">不可选</text> -->
28 <text v-if="n.canChoose == 1" class="text-primary" @click="handleChoose(n)">选择</text> 28 <text v-else-if="n.canChoose == 1" class="text-primary" @click="handleChoose(n)">选择</text>
29 <text v-else class="text-gray">不可选</text>
29 </view> 30 </view>
30 </view> 31 </view>
31 </view> 32 </view>
...@@ -146,6 +147,15 @@ ...@@ -146,6 +147,15 @@
146 } 147 }
147 148
148 function handleChoose(row) { 149 function handleChoose(row) {
150 // 校验是否已被其他位置选中
151 if (isChosen(row)) {
152 uni.showToast({
153 title: '该考官已被选中,不能重复选择',
154 icon: 'none'
155 })
156 return
157 }
158
149 if (row.canChoose != 1) { 159 if (row.canChoose != 1) {
150 uni.showToast({ 160 uni.showToast({
151 title: '该考官资质已过期!', 161 title: '该考官资质已过期!',
...@@ -215,7 +225,7 @@ ...@@ -215,7 +225,7 @@
215 success: (res) => { 225 success: (res) => {
216 if (res.confirm) { 226 if (res.confirm) {
217 uni.showLoading({ title: '添加中' }) 227 uni.showLoading({ title: '添加中' })
218 api.selfAdd(app.globalData.memberInfo.memId, row.perId).then(() => { 228 api.selfAdd(row.perId).then(() => {
219 uni.hideLoading() 229 uni.hideLoading()
220 uni.showToast({ title: '添加成功', icon: 'success' }) 230 uni.showToast({ title: '添加成功', icon: 'success' })
221 addPopup.value.close() 231 addPopup.value.close()
...@@ -317,6 +327,11 @@ ...@@ -317,6 +327,11 @@
317 color: #999; 327 color: #999;
318 } 328 }
319 329
330 .text-chosen {
331 color: #AD181F;
332 font-weight: bold;
333 }
334
320 .text-danger { 335 .text-danger {
321 color: #dd524d; 336 color: #dd524d;
322 } 337 }
......
1 <template>
2 <view class="settlement-audit-page">
3 <!-- Tab 切换 -->
4 <view class="tab-bar">
5 <view
6 v-for="tab in tabs"
7 :key="tab.value"
8 :class="['tab-item', { active: status === tab.value }]"
9 @click="onTabChange(tab.value)"
10 >
11 {{ tab.text }}
12 </view>
13 </view>
14
15 <!-- 列表区域 -->
16 <scroll-view scroll-y class="list-container" @scrolltolower="loadMore">
17 <view v-for="item in infoList" :key="item.id" class="list-item">
18 <!-- 选择框 -->
19 <view class="checkbox-wrap">
20 <checkbox-group @change="onCheckboxChange(item.id)">
21 <label>
22 <checkbox :value="item.id" :checked="isChecked(item.id)" :disabled="item.status != '1'" color="#C4121B" />
23 </label>
24 </checkbox-group>
25 </view>
26
27 <!-- 头部信息 -->
28 <view class="item-header">
29 <text class="code" @click="goDetail(item)">{{ item.code }}</text>
30 <text :class="['status-tag', 'status-' + item.status]">{{ statusArr[item.status] }}</text>
31 </view>
32
33 <!-- 主体信息 -->
34 <view class="item-body">
35 <view class="info-row">
36 <text class="label">结算名称</text>
37 <text class="value">{{ item.name }}</text>
38 </view>
39 <view class="info-row">
40 <text class="label">结算单位</text>
41 <text class="value">{{ item.memName }}</text>
42 </view>
43 <view class="info-row">
44 <text class="label">考试人数</text>
45 <text class="value">{{ item.personCount }}</text>
46 </view>
47 <view class="info-row">
48 <text class="label">费用合计</text>
49 <text class="value primary">¥{{ item.originPrice }}</text>
50 </view>
51 <view class="info-row">
52 <text class="label">结算金额</text>
53 <text class="value red">¥{{ item.price }}</text>
54 </view>
55 <view class="info-row">
56 <text class="label">结算状态</text>
57 <text :class="['value', item.status == '2' ? 'green' : item.status == '3' ? 'red' : '']">{{ item.verityStatusStr }}</text>
58 </view>
59 </view>
60
61 <!-- 底部信息 -->
62 <view class="item-footer">
63 <view class="footer-left">
64 <text class="date">提交: {{ formatDate(item.commitTime) }}</text>
65 <text v-if="item.auditTime" class="date">审核: {{ formatDate(item.auditTime) }}</text>
66 </view>
67 <view class="footer-right">
68 <text v-if="item.fileUrl" class="invoice-btn" @click="downloadInvoice(item)">发票</text>
69 <view v-else class="invoice-btn disabled">发票</view>
70 <button
71 v-if="item.status == '1'"
72 class="btn-settle"
73 @click="openSettlement(item)"
74 >结算</button>
75 </view>
76 </view>
77 </view>
78
79 <!-- 空状态 -->
80 <view v-if="infoList.length === 0 && !loading" class="empty">
81 <text>暂无数据</text>
82 </view>
83
84 <!-- 加载更多 -->
85 <view v-if="loading" class="loading-more">
86 <text>加载中...</text>
87 </view>
88 <view v-if="noMore && infoList.length > 0" class="loading-more">
89 <text>没有更多了</text>
90 </view>
91 </scroll-view>
92
93 <!-- 底部统计和批量按钮 -->
94 <view v-if="selectedIds.length > 0" class="bottom-bar">
95 <view class="stat-left">
96 <text class="stat-item">人数: <text class="value">{{ selectedStatistical.personCount }}</text></text>
97 <text class="stat-item">费用: <text class="value">¥{{ selectedStatistical.originPrice?.toFixed(2) }}</text></text>
98 <text class="stat-item">结算: <text class="value red">¥{{ selectedStatistical.price?.toFixed(2) }}</text></text>
99 </view>
100 <view class="btn-right">
101 <button class="batch-btn" @click="openBatchSettlement">
102 批量结算审核 ({{ selectedIds.length }})
103 </button>
104 </view>
105 </view>
106 </view>
107 </template>
108
109 <script setup>
110 import { ref, computed, onMounted } from 'vue'
111 import {onShow} from '@dcloudio/uni-app'
112 import * as api from '@/common/api.js'
113 import config from '@/config.js'
114 import _ from 'underscore'
115
116 const tabs = ref([
117 { value: '', text: '全部' },
118 { value: '1', text: '待结算' },
119 { value: '2', text: '结算通过' },
120 { value: '3', text: '结算拒绝' }
121 ])
122 const statusArr = ref(['未提交', '待结算', '结算通过', '结算拒绝'])
123 const status = ref('')
124 const infoList = ref([])
125 const loading = ref(false)
126 const noMore = ref(false)
127 const pageNum = ref(1)
128 const pageSize = ref(10)
129 const total = ref(0)
130
131 const selectedIds = ref([])
132
133 const statistical = ref({
134 personCount: 0,
135 originPrice: 0,
136 price: 0
137 })
138
139 // 选中项的统计
140 const selectedStatistical = computed(() => {
141 let personCount = 0
142 let originPrice = 0
143 let price = 0
144 _.each(infoList.value, (info) => {
145 if (selectedIds.value.includes(info.id)) {
146 personCount += (info.personCount * 1)
147 originPrice += (info.originPrice * 1)
148 price += (info.price * 1)
149 }
150 })
151 return { personCount, originPrice, price }
152 })
153
154 onMounted(() => {
155 getList()
156 })
157
158 function onTabChange(value) {
159 status.value = value
160 pageNum.value = 1
161 infoList.value = []
162 selectedIds.value = []
163 noMore.value = false
164 getList()
165 }
166
167 async function getList() {
168 if (loading.value) return
169 loading.value = true
170
171 try {
172 const params = {
173 status: status.value,
174 pageNum: pageNum.value,
175 pageSize: pageSize.value
176 }
177
178 const res = await api.settlementList(params)
179
180 if (pageNum.value === 1) {
181 infoList.value = res.rows || []
182 } else {
183 infoList.value = [...infoList.value, ...(res.rows || [])]
184 }
185
186 total.value = res.total || 0
187 noMore.value = infoList.value.length >= total.value
188
189 // 计算统计
190 calculateStatistical()
191 } catch (err) {
192 console.error('获取结算列表失败', err)
193 } finally {
194 loading.value = false
195 }
196 }
197
198 function calculateStatistical() {
199 statistical.value = {
200 personCount: 0,
201 originPrice: 0,
202 price: 0
203 }
204 _.each(infoList.value, (info) => {
205 statistical.value.personCount += (info.personCount * 1)
206 statistical.value.originPrice += (info.originPrice * 1)
207 statistical.value.price += (info.price * 1)
208 })
209 }
210
211 function loadMore() {
212 if (!noMore.value && !loading.value) {
213 pageNum.value++
214 getList()
215 }
216 }
217
218 function formatDate(dateStr) {
219 if (!dateStr) return '-'
220 return dateStr.substring(0, 10)
221 }
222
223 // 复选框选择
224 function onCheckboxChange(id) {
225 const index = selectedIds.value.indexOf(id)
226 if (index > -1) {
227 selectedIds.value.splice(index, 1)
228 } else {
229 selectedIds.value.push(id)
230 }
231 }
232
233 function isChecked(id) {
234 return selectedIds.value.includes(id)
235 }
236
237 // 进入详情页
238 function goDetail(item) {
239 const data = encodeURIComponent(JSON.stringify(item))
240 uni.navigateTo({
241 url: `/level/settlementView?data=${data}`
242 })
243 }
244
245 // 下载发票
246 function downloadInvoice(item) {
247 if (!item.fileUrl) {
248 uni.showToast({ title: '暂无发票', icon: 'none' })
249 return
250 }
251 try {
252 const invoice = JSON.parse(item.fileUrl)
253 if (invoice && invoice[0]?.url) {
254 let fileUrl = invoice[0].url
255 // 确保 URL 格式正确
256 if (!fileUrl.startsWith('http')) {
257 fileUrl = config.baseUrl_api + fileUrl
258 }
259
260 // 小程序中使用 previewImage 预览,让用户长按保存
261 uni.previewImage({
262 urls: [fileUrl],
263 success: () => {
264 console.log('previewImage success')
265 },
266 fail: (err) => {
267 console.error('previewImage fail:', err)
268 uni.showToast({ title: '打开图片失败', icon: 'none' })
269 }
270 })
271 } else {
272 uni.showToast({ title: '发票文件不存在', icon: 'none' })
273 }
274 } catch (e) {
275 console.error('解析发票数据失败', e)
276 uni.showToast({ title: '解析发票数据失败', icon: 'none' })
277 }
278 }
279
280 // 打开结算审核 - 跳转到审核页面
281 function openSettlement(item) {
282 const ids = item.id
283 uni.navigateTo({
284 url: `/pages/rank/scoreAudit?ids=${ids}&pageType=3`
285 })
286 }
287
288 // 批量结算审核 - 跳转到审核页面
289 function openBatchSettlement() {
290 if (selectedIds.value.length === 0) {
291 uni.showToast({ title: '请先选择要结算的项目', icon: 'none' })
292 return
293 }
294 const ids = selectedIds.value.join(',')
295 uni.navigateTo({
296 url: `/pages/rank/scoreAudit?ids=${ids}&pageType=3`
297 })
298 }
299
300 function handleQuery() {
301 pageNum.value = 1
302 infoList.value = []
303 noMore.value = false
304 getList()
305 }
306
307 // 页面显示时刷新列表
308 onShow(() => {
309 handleQuery()
310 })
311 </script>
312
313 <style lang="scss" scoped>
314 .settlement-audit-page {
315 min-height: 100vh;
316 background: #f5f5f5;
317 }
318
319 /* Tab 切换 */
320 .tab-bar {
321 display: flex;
322 background: #fff;
323 padding: 20rpx 0;
324
325 .tab-item {
326 flex: 1;
327 text-align: center;
328 font-size: 28rpx;
329 color: #666;
330 position: relative;
331
332 &.active {
333 color: #C4121B;
334 font-weight: 600;
335
336 &::after {
337 content: '';
338 position: absolute;
339 bottom: -10rpx;
340 left: 50%;
341 transform: translateX(-50%);
342 width: 60rpx;
343 height: 4rpx;
344 background: #C4121B;
345 border-radius: 2rpx;
346 }
347 }
348 }
349 }
350
351 /* 列表区域 */
352 .list-container {
353 height: calc(100vh - 180rpx);
354 }
355
356 .list-item {
357 position: relative;
358 background: #fff;
359 margin: 20rpx 30rpx;
360 border-radius: 12rpx;
361 padding: 24rpx;
362 }
363
364 /* 复选框 */
365 .checkbox-wrap {
366 position: absolute;
367 top: 44rpx;
368 left: 20rpx;
369 transform: translateY(-50%);
370 z-index: 10;
371 }
372
373 .item-header {
374 display: flex;
375 justify-content: space-between;
376 align-items: center;
377 margin-bottom: 16rpx;
378 padding-left: 60rpx;
379
380 .code {
381 font-size: 30rpx;
382 color: #1561cb;
383 font-weight: 600;
384 }
385
386 .status-tag {
387 font-size: 24rpx;
388 padding: 4rpx 16rpx;
389 border-radius: 20rpx;
390
391 &.status-1 { background: #fff3e0; color: #ff9800; }
392 &.status-2 { background: #e8f5e9; color: #4caf50; }
393 &.status-3 { background: #ffebee; color: #f44336; }
394 }
395 }
396
397 .item-body {
398 .info-row {
399 display: flex;
400 justify-content: space-between;
401 padding: 6rpx 0;
402
403 .label {
404 font-size: 26rpx;
405 color: #666;
406 }
407
408 .value {
409 font-size: 26rpx;
410 color: #333;
411
412 &.primary { color: #333; }
413 &.red { color: #C4121B; font-weight: 600; }
414 &.green { color: #4caf50; font-weight: 600; }
415 }
416 }
417 }
418
419 .item-footer {
420 display: flex;
421 justify-content: space-between;
422 align-items: center;
423 margin-top: 16rpx;
424 padding-top: 16rpx;
425 border-top: 1rpx solid #f0f0f0;
426
427 .footer-left {
428 display: flex;
429 flex-direction: column;
430
431 .date {
432 font-size: 24rpx;
433 color: #999;
434 margin-bottom: 4rpx;
435 }
436 }
437
438 .footer-right {
439 display: flex;
440 align-items: center;
441 gap: 16rpx;
442
443 .invoice-btn {
444 font-size: 26rpx;
445 color: #1561cb;
446
447 &.disabled {
448 color: #ccc;
449 }
450 }
451
452 .btn-settle {
453 padding: 0rpx 20rpx;
454 background: #fff;
455 color: #C4121B;
456 font-size: 24rpx;
457 border: 2rpx solid #C4121B;
458 border-radius: 35rpx;
459 width: 150rpx;
460
461 &::after {
462 border: none;
463 }
464 }
465 }
466 }
467
468 /* 空状态 */
469 .empty {
470 text-align: center;
471 padding: 100rpx 0;
472 color: #999;
473 font-size: 28rpx;
474 }
475
476 .loading-more {
477 text-align: center;
478 padding: 20rpx;
479 color: #999;
480 font-size: 24rpx;
481 }
482
483 /* 底部栏 */
484 .bottom-bar {
485 position: fixed;
486 bottom: 0;
487 left: 0;
488 right: 0;
489 display: flex;
490 align-items: center;
491 padding: 30rpx;
492 background: #fff;
493 border-top: 1rpx solid #eee;
494 box-sizing: border-box;
495
496 .stat-left {
497 flex: 1;
498 display: flex;
499 gap: 20rpx;
500
501 .stat-item {
502 font-size: 24rpx;
503 color: #666;
504
505 .value {
506 font-weight: 600;
507 color: #333;
508
509 &.red {
510 color: #C4121B;
511 }
512 }
513 }
514 }
515
516 .btn-right {
517 .batch-btn {
518 padding: 0rpx 30rpx;
519 background: #C4121B;
520 color: #fff;
521 font-size: 28rpx;
522 border-radius: 40rpx;
523
524 &::after {
525 border: none;
526 }
527 }
528 }
529 }
530 </style>
1 <template>
2 <view>
3 <scroll-view scroll-y class="detail-content">
4 <!-- 结算基本信息 -->
5 <view class="card">
6 <view class="card-header">
7 <view class="header-left">结算信息</view>
8 </view>
9 <view class="card-body">
10 <view class="info-row">
11 <text class="label">结算编号</text>
12 <text class="value">{{ form.code || '--' }}</text>
13 </view>
14 <view class="info-row">
15 <text class="label">缴费名称</text>
16 <text class="value">{{ form.name || '--' }}</text>
17 </view>
18 <view class="info-row">
19 <text class="label">缴费单位</text>
20 <text class="value">{{ form.memName || '--' }}</text>
21 </view>
22 <view class="info-row">
23 <text class="label">考试人数</text>
24 <text class="value">{{ form.personCount || 0 }}</text>
25 </view>
26 <view class="info-row">
27 <text class="label">费用合计</text>
28 <text class="value">¥{{ form.originPrice || 0 }}</text>
29 </view>
30 <view class="info-row">
31 <text class="label">结算金额</text>
32 <text class="value text-red">¥{{ form.price || 0 }}</text>
33 </view>
34 <view class="info-row">
35 <text class="label">支付方式</text>
36 <text class="value">民生付</text>
37 </view>
38 <view class="info-row">
39 <text class="label">提交日期</text>
40 <text class="value">{{ formatDate(form.commitTime) }}</text>
41 </view>
42 <view class="info-row">
43 <text class="label">结算日期</text>
44 <text class="value">{{ formatDate(form.auditTime) }}</text>
45 </view>
46 <view class="info-row" v-if="form.fileUrl">
47 <text class="label">发票</text>
48 <text class="value text-primary" @click="downloadInvoice">下载发票</text>
49 </view>
50 </view>
51 </view>
52
53 <!-- 关联缴费单 -->
54 <view class="card">
55 <view class="card-header">
56 <view class="header-left">关联缴费单</view>
57 </view>
58 <!-- 统计信息 -->
59 <view class="payment-stat" v-if="paymentList.length > 0">
60 <text>费用合计: <text class="stat-value">¥{{ paymentStat.totalAmount?.toFixed(2) }}</text></text>
61 <text>人数合计: <text class="stat-value">{{ paymentStat.totalNum }}</text></text>
62 </view>
63 <view v-if="loadingPayment" class="state-tip">加载中...</view>
64 <view v-else-if="paymentList.length === 0" class="state-tip">暂无关联缴费单</view>
65 <view class="payment-list" v-else>
66 <view class="payment-item" v-for="(pay, index) in paymentList" :key="pay.payId">
67 <!-- 头部:序号 + 名称 + 状态 -->
68 <view class="item-header">
69 <!-- <view class="item-index">{{ index + 1 }}</view> -->
70 <view class="item-name">{{ pay.name }}</view>
71 <view :class="['status-tag', pay.submitId ? 'passed' : 'pending']">
72 {{ pay.submitId ? '已结算' : '未结算' }}
73 </view>
74 </view>
75 <!-- 主体:单列列表 -->
76 <view class="item-body">
77 <view class="info-line">
78 <text class="info-label">缴费编号</text>
79 <text class="info-value">{{ pay.payCode || '--' }}</text>
80 </view>
81 <view class="info-line">
82 <text class="info-label">缴费单位</text>
83 <text class="info-value">{{ pay.memberName || '--' }}</text>
84 </view>
85 <view class="info-line">
86 <text class="info-label">考试人数</text>
87 <text class="info-value">{{ pay.totalNum || 0 }}</text>
88 </view>
89 <view class="info-line">
90 <text class="info-label">总金额</text>
91 <text class="info-value text-red">¥{{ pay.totalAmount || 0 }}</text>
92 </view>
93 <view class="info-line">
94 <text class="info-label">支付方式</text>
95 <text class="info-value">民生付</text>
96 </view>
97 <view class="info-line">
98 <text class="info-label">审核状态</text>
99 <text :class="['info-value', getVerifyStatusClass(pay.verityStatus)]">{{ pay.verityStatusStr || '--' }}</text>
100 </view>
101 <view class="info-line">
102 <text class="info-label">提交日期</text>
103 <text class="info-value">{{ formatDate(pay.submitTime) }}</text>
104 </view>
105 <view class="info-line">
106 <text class="info-label">审核日期</text>
107 <text class="info-value">{{ formatDate(pay.verityDate) }}</text>
108 </view>
109 </view>
110 </view>
111 </view>
112 </view>
113 </scroll-view>
114 </view>
115 </template>
116
117 <script setup>
118 import { ref, onMounted } from 'vue'
119 import { onLoad } from '@dcloudio/uni-app'
120 import * as api from '@/common/api.js'
121 import config from '@/config.js'
122
123 const loading = ref(false)
124 const loadingPayment = ref(false)
125 const form = ref({})
126 const paymentList = ref([])
127 const paymentStat = ref({
128 totalAmount: 0,
129 totalNum: 0
130 })
131
132 onLoad((options) => {
133 if (options.data) {
134 try {
135 form.value = JSON.parse(decodeURIComponent(options.data))
136 } catch (e) {
137 console.error('解析结算数据失败', e)
138 }
139 }
140 })
141
142 onMounted(() => {
143 if (form.value.payids) {
144 getPaymentList()
145 }
146 })
147
148 async function getPaymentList() {
149 loadingPayment.value = true
150 paymentStat.value = { totalAmount: 0, totalNum: 0 }
151 try {
152 const res = await api.settlementDetailList({ payIds: form.value.payids ,type:1 })
153 paymentList.value = res.rows || []
154 // 计算统计
155 let totalAmount = 0
156 let totalNum = 0
157 for (const pay of paymentList.value) {
158 totalAmount += (pay.totalAmount * 1) || 0
159 totalNum += (pay.totalNum * 1) || 0
160 }
161 paymentStat.value = { totalAmount, totalNum }
162 } catch (err) {
163 console.error('获取缴费单列表失败', err)
164 paymentList.value = []
165 } finally {
166 loadingPayment.value = false
167 }
168 }
169
170 function formatDate(dateStr) {
171 if (!dateStr) return '--'
172 if (typeof dateStr === 'string' && dateStr.indexOf('T') > -1) {
173 return dateStr.slice(0, 10)
174 }
175 return dateStr
176 }
177
178 function getVerifyStatusClass(status) {
179 if (status == '1') return 'text-success'
180 if (status == '2') return 'text-danger'
181 if (status == '3') return 'text-warning'
182 return ''
183 }
184
185 function downloadInvoice() {
186 if (!form.value.fileUrl) {
187 uni.showToast({ title: '暂无发票', icon: 'none' })
188 return
189 }
190 try {
191 const invoice = JSON.parse(form.value.fileUrl)
192 if (invoice && invoice[0]?.url) {
193 let fileUrl = invoice[0].url
194 if (!fileUrl.startsWith('http')) {
195 fileUrl = config.baseUrl_api + fileUrl
196 }
197 uni.previewImage({
198 urls: [fileUrl],
199 success: () => {
200 console.log('previewImage success')
201 },
202 fail: (err) => {
203 console.error('previewImage fail:', err)
204 uni.showToast({ title: '打开图片失败', icon: 'none' })
205 }
206 })
207 }
208 } catch (e) {
209 console.error('解析发票数据失败', e)
210 uni.showToast({ title: '解析发票数据失败', icon: 'none' })
211 }
212 }
213 </script>
214
215 <style scoped lang="scss">
216 // 颜色变量
217 $primary-color: #C4121B;
218 $success-color: #52c41a;
219 $bg-color: #f5f5f5;
220 $card-bg: #ffffff;
221 $text-primary: #333;
222 $text-secondary: #666;
223 $text-placeholder: #999;
224 $border-color: #eee;
225
226 .detail-content {
227 padding: 20rpx;
228 background: $bg-color;
229 min-height: 100vh;
230 box-sizing: border-box;
231 }
232
233 .card {
234 background: $card-bg;
235 border-radius: 16rpx;
236 margin-bottom: 20rpx;
237 overflow: hidden;
238 box-shadow: 0 4rpx 12rpx rgba(0, 0, 0, 0.05);
239 }
240
241 .card-header {
242 display: flex;
243 justify-content: space-between;
244 align-items: center;
245 padding: 24rpx 24rpx 20rpx;
246 border-bottom: 1rpx solid $border-color;
247
248 .header-left {
249 font-size: 30rpx;
250 font-weight: 600;
251 color: $text-primary;
252 }
253 }
254
255 .card-body {
256 padding: 8rpx 24rpx 24rpx;
257 }
258
259 .info-row {
260 display: flex;
261 justify-content: space-between;
262 align-items: center;
263 padding: 18rpx 0;
264 border-bottom: 1rpx solid #f5f5f5;
265
266 &:last-child {
267 border-bottom: none;
268 }
269
270 .label {
271 font-size: 28rpx;
272 color: $text-placeholder;
273 flex-shrink: 0;
274 width: 170rpx;
275 }
276
277 .value {
278 font-size: 28rpx;
279 color: $text-primary;
280 text-align: right;
281 flex: 1;
282 word-break: break-all;
283 }
284 }
285
286 .text-red {
287 color: $primary-color !important;
288 font-weight: 600;
289 }
290
291 .text-primary {
292 color: #1561cb !important;
293 }
294
295 .state-tip {
296 text-align: center;
297 padding: 60rpx 0;
298 font-size: 26rpx;
299 color: $text-placeholder;
300 }
301
302 .payment-stat {
303 display: flex;
304 justify-content: space-between;
305 padding: 20rpx 24rpx;
306 background: #FFF0F0;
307 border-bottom: 1rpx solid $border-color;
308 font-size: 26rpx;
309 color: $text-secondary;
310
311 .stat-value {
312 color: $primary-color;
313 font-weight: 600;
314 }
315 }
316
317 .payment-list {
318 padding: 0 24rpx 24rpx;
319 }
320
321 .payment-item {
322 border-radius: 12rpx;
323 padding: 24rpx;
324 margin-top: 16rpx;
325 border: 1rpx solid $border-color;
326 background: #fff;
327
328 .item-header {
329 display: flex;
330 align-items: center;
331 margin-bottom: 20rpx;
332 padding-bottom: 16rpx;
333 border-bottom: 1rpx solid #f5f5f5;
334
335 .item-index {
336 width: 40rpx;
337 height: 40rpx;
338 line-height: 40rpx;
339 text-align: center;
340 font-size: 22rpx;
341 color: #fff;
342 background: $primary-color;
343 border-radius: 50%;
344 margin-right: 16rpx;
345 }
346
347 .item-name {
348 flex: 1;
349 font-size: 28rpx;
350 font-weight: 600;
351 color: $text-primary;
352 }
353
354 .status-tag {
355 font-size: 22rpx;
356 padding: 4rpx 16rpx;
357 border-radius: 20rpx;
358
359 &.passed {
360 background: rgba($success-color, 0.1);
361 color: $success-color;
362 }
363
364 &.pending {
365 background: rgba($primary-color, 0.1);
366 color: $primary-color;
367 }
368 }
369 }
370
371 .item-body {
372 .info-line {
373 display: flex;
374 justify-content: space-between;
375 align-items: center;
376 padding: 12rpx 0;
377 border-bottom: 1rpx solid #f5f5f5;
378
379 &:last-child {
380 border-bottom: none;
381 }
382
383 .info-label {
384 font-size: 26rpx;
385 color: $text-placeholder;
386 flex-shrink: 0;
387 }
388
389 .info-value {
390 font-size: 26rpx;
391 color: $text-primary;
392 text-align: right;
393 flex: 1;
394 margin-left: 24rpx;
395 word-break: break-all;
396 }
397 }
398 }
399 }
400 </style>
...@@ -63,7 +63,7 @@ ...@@ -63,7 +63,7 @@
63 <button class="btn-red" @click="login">登录</button> 63 <button class="btn-red" @click="login">登录</button>
64 </view> 64 </view>
65 <view class="center-item"> 65 <view class="center-item">
66 <text class="text-red" @click="goRegister">没有账号,去注册</text> 66 <button class="btn-red btn-register" @click="goRegister">没有账号,去注册</button>
67 </view> 67 </view>
68 </view> 68 </view>
69 <view class="wNumber"> 69 <view class="wNumber">
...@@ -84,6 +84,25 @@ ...@@ -84,6 +84,25 @@
84 <image v-else src="@/static/login/xz2@2x.png"></image> 84 <image v-else src="@/static/login/xz2@2x.png"></image>
85 <view>登录即代表您同意<text>《用户协议》</text><text>《隐私策略》</text></view> --> 85 <view>登录即代表您同意<text>《用户协议》</text><text>《隐私策略》</text></view> -->
86 </view> 86 </view>
87
88 <!-- 注册提示弹框 -->
89 <uni-popup ref="registerPopup" type="center" :mask-click="false">
90 <view class="register-popup">
91 <view class="popup-title">注册提示</view>
92 <view class="popup-content">
93 <view class="popup-text">请准备以下材料,以便顺利完成注册</view>
94 <view class="popup-list">
95 <text>1. 单位营业执照(清晰照片)</text>
96 <text>2. 法人身份证正反面照片(清晰照片)</text>
97 <text>3. 单位营业执照(清晰照片)</text>
98 </view>
99 </view>
100 <view class="popup-btns">
101 <view class="popup-btn cancel" @click="closeRegisterPopup">取消</view>
102 <view class="popup-btn confirm" @click="confirmRegister">确定</view>
103 </view>
104 </view>
105 </uni-popup>
87 </view> 106 </view>
88 </template> 107 </template>
89 108
...@@ -107,6 +126,7 @@ const agree = ref(false) ...@@ -107,6 +126,7 @@ const agree = ref(false)
107 const isRember = ref(true) 126 const isRember = ref(true)
108 const loading = ref(false) 127 const loading = ref(false)
109 const codeUrl = ref(null) 128 const codeUrl = ref(null)
129 const registerPopup = ref(null)
110 const inputstyle = ref({ 130 const inputstyle = ref({
111 borderColor: 'transparent', 131 borderColor: 'transparent',
112 fontSize: '30rpx' 132 fontSize: '30rpx'
...@@ -226,9 +246,17 @@ function login() { ...@@ -226,9 +246,17 @@ function login() {
226 } 246 }
227 247
228 function goRegister() { 248 function goRegister() {
229 const path = '/login/register' 249 registerPopup.value.open()
250 }
251
252 function closeRegisterPopup() {
253 registerPopup.value.close()
254 }
255
256 function confirmRegister() {
257 registerPopup.value.close()
230 uni.navigateTo({ 258 uni.navigateTo({
231 url: path 259 url: '/login/register'
232 }) 260 })
233 } 261 }
234 262
...@@ -517,4 +545,78 @@ function call(num) { ...@@ -517,4 +545,78 @@ function call(num) {
517 margin-right: 20rpx; 545 margin-right: 20rpx;
518 } 546 }
519 } 547 }
548
549 /* 注册按钮 */
550 .btn-register {
551 border-radius: 40rpx;
552 width: 600rpx;
553 line-height: 80rpx;
554 font-size: 36rpx;
555 background: #fff;
556 color: #AD181F;
557 border: 1rpx solid #AD181F;
558 margin: 0;
559 }
560
561 /* 注册提示弹框 */
562 .register-popup {
563 width: 600rpx;
564 background: #ffffff;
565 border-radius: 24rpx;
566 overflow: hidden;
567 }
568
569 .popup-title {
570 font-size: 32rpx;
571 font-weight: 500;
572 color: #333;
573 text-align: center;
574 padding: 40rpx 30rpx 20rpx;
575 }
576
577 .popup-content {
578 padding: 20rpx 30rpx 40rpx;
579 }
580
581 .popup-text {
582 font-size: 28rpx;
583 color: #333;
584 margin-bottom: 20rpx;
585 }
586
587 .popup-list {
588 display: flex;
589 flex-direction: column;
590 gap: 16rpx;
591 padding-left: 10rpx;
592 }
593
594 .popup-list text {
595 font-size: 26rpx;
596 color: #666;
597 line-height: 1.5;
598 }
599
600 .popup-btns {
601 display: flex;
602 border-top: 1rpx solid #eee;
603 }
604
605 .popup-btn {
606 flex: 1;
607 height: 100rpx;
608 line-height: 100rpx;
609 text-align: center;
610 font-size: 30rpx;
611 }
612
613 .popup-btn.cancel {
614 color: #666;
615 border-right: 1rpx solid #eee;
616 }
617
618 .popup-btn.confirm {
619 color: #AD181F;
620 font-weight: 500;
621 }
520 </style> 622 </style>
......
...@@ -12,19 +12,19 @@ ...@@ -12,19 +12,19 @@
12 <form> 12 <form>
13 <view class="round-input-item"> 13 <view class="round-input-item">
14 <image class="icon" :src="config.baseUrl_api+'/fs/static/login/tag01@2x.png'"></image> 14 <image class="icon" :src="config.baseUrl_api+'/fs/static/login/tag01@2x.png'"></image>
15 <uni-easyinput :styles="inputstyle" v-model="registerForm.telNo" placeholder="请输入手机号" /> 15 <uni-easyinput :styles="inputstyle" v-model="registerForm.telNo" placeholder="请输入手机号" @blur="validateTelNo" />
16 </view> 16 </view>
17 <view class="round-input-item"> 17 <view class="round-input-item">
18 <image class="icon" :src="config.baseUrl_api+'/fs/static/login/tag02@2x.png'"></image> 18 <image class="icon" :src="config.baseUrl_api+'/fs/static/login/tag02@2x.png'"></image>
19 <uni-easyinput :styles="inputstyle" v-model="registerForm.password" placeholder="密码" type="password"/> 19 <uni-easyinput :styles="inputstyle" v-model="registerForm.password" placeholder="密码" type="password" @blur="validatePassword" />
20 </view> 20 </view>
21 <view class="round-input-item"> 21 <view class="round-input-item">
22 <image class="icon" :src="config.baseUrl_api+'/fs/static/login/tag03@2x.png'"></image> 22 <image class="icon" :src="config.baseUrl_api+'/fs/static/login/tag03@2x.png'"></image>
23 <uni-easyinput :styles="inputstyle" v-model="registerForm.password2" placeholder="确认密码" type="password"/> 23 <uni-easyinput :styles="inputstyle" v-model="registerForm.password2" placeholder="确认密码" type="password" @blur="validatePassword2" />
24 </view> 24 </view>
25 <view class="round-input-item"> 25 <view class="round-input-item">
26 <image class="icon" :src="config.baseUrl_api+'/fs/static/login/tag03@2x.png'"></image> 26 <image class="icon" :src="config.baseUrl_api+'/fs/static/login/tag03@2x.png'"></image>
27 <uni-easyinput :styles="inputstyle" placeholder="图形验证码" v-model="registerForm.captcha" /> 27 <uni-easyinput :styles="inputstyle" placeholder="图形验证码" v-model="registerForm.captcha" @blur="validateCaptcha" />
28 <image :src="codeUrl" @click="getCode" /> 28 <image :src="codeUrl" @click="getCode" />
29 </view> 29 </view>
30 <view class="round-input-item"> 30 <view class="round-input-item">
...@@ -138,12 +138,20 @@ function register() { ...@@ -138,12 +138,20 @@ function register() {
138 138
139 groupMemberRegister(registerForm.value) 139 groupMemberRegister(registerForm.value)
140 .then((res) => { 140 .then((res) => {
141 uni.showToast({ 141 uni.showModal({
142 title: `恭喜你,您的账号 ${registerForm.value.telNo} 注册成功!`, 142 title: '提示',
143 icon: 'none' 143 content: `恭喜你,您的账号 ${registerForm.value.telNo} 注册成功!`,
144 }) 144 confirmText: '去登录',
145 cancelText: '取消',
146 success: (res) => {
147 if (res.confirm) {
145 registerForm.value = {} 148 registerForm.value = {}
146 setTimeout(goLogin, 2000) 149 goLogin()
150 } else {
151 // 取消,保持当前页面
152 }
153 }
154 })
147 }) 155 })
148 } 156 }
149 157
...@@ -160,6 +168,58 @@ function validPassword(pwd) { ...@@ -160,6 +168,58 @@ function validPassword(pwd) {
160 return (lowerRegex.test(pwd) && upperRegex.test(pwd) && digitRegex.test(pwd) && symbolRegex.test(pwd) && specific.test(pwd)) 168 return (lowerRegex.test(pwd) && upperRegex.test(pwd) && digitRegex.test(pwd) && symbolRegex.test(pwd) && specific.test(pwd))
161 } 169 }
162 170
171 // 手机号校验
172 function validateTelNo() {
173 const telNo = registerForm.value.telNo
174 if (!telNo) {
175 uni.showToast({ title: '手机号不能为空', icon: 'none' })
176 return false
177 }
178 if (!/^1[3-9]\d{9}$/.test(telNo)) {
179 uni.showToast({ title: '手机号格式不正确', icon: 'none' })
180 return false
181 }
182 return true
183 }
184
185 // 密码校验
186 function validatePassword() {
187 const password = registerForm.value.password
188 if (!password) {
189 uni.showToast({ title: '密码不能为空', icon: 'none' })
190 return false
191 }
192 if (!validPassword(password)) {
193 uni.showToast({ title: '密码必须为8~18位大小写字母、数字和特殊符号组合', icon: 'none', duration: 3000 })
194 return false
195 }
196 return true
197 }
198
199 // 确认密码校验
200 function validatePassword2() {
201 const password2 = registerForm.value.password2
202 if (!password2) {
203 uni.showToast({ title: '确认密码不能为空', icon: 'none' })
204 return false
205 }
206 if (registerForm.value.password && password2 !== registerForm.value.password) {
207 uni.showToast({ title: '两次密码不一致', icon: 'none' })
208 return false
209 }
210 return true
211 }
212
213 // 图形验证码校验
214 function validateCaptcha() {
215 const captcha = registerForm.value.captcha
216 if (!captcha) {
217 uni.showToast({ title: '图形验证码不能为空', icon: 'none' })
218 return false
219 }
220 return true
221 }
222
163 function goLogin() { 223 function goLogin() {
164 let path = '/login/loginC'; 224 let path = '/login/loginC';
165 uni.navigateTo({ 225 uni.navigateTo({
......
...@@ -51,7 +51,7 @@ ...@@ -51,7 +51,7 @@
51 </uni-list-item> 51 </uni-list-item>
52 <uni-list-item v-if="form.menCode" :rightText="form.menCode" title="会员编号"/> 52 <uni-list-item v-if="form.menCode" :rightText="form.menCode" title="会员编号"/>
53 <uni-list-item :rightText="form.name" title="机构名称"/> 53 <uni-list-item :rightText="form.name" title="机构名称"/>
54 <uni-list-item title="所属省份"> 54 <!-- <uni-list-item title="所属省份">
55 <template v-slot:footer> 55 <template v-slot:footer>
56 <view class="frrr"> 56 <view class="frrr">
57 <uni-data-picker v-model="form.belongProvinceId" :clear-icon="false" :localdata="options" 57 <uni-data-picker v-model="form.belongProvinceId" :clear-icon="false" :localdata="options"
...@@ -59,7 +59,7 @@ ...@@ -59,7 +59,7 @@
59 </uni-data-picker> 59 </uni-data-picker>
60 </view> 60 </view>
61 </template> 61 </template>
62 </uni-list-item> 62 </uni-list-item> -->
63 <uni-list-item 63 <uni-list-item
64 v-if="authenticationStatusa != 1&&authenticationStatusa != 0&&authenticationStatusa != 3&&newResult||form.associateId&&form.associateId>0||activeStatus==1" 64 v-if="authenticationStatusa != 1&&authenticationStatusa != 0&&authenticationStatusa != 3&&newResult||form.associateId&&form.associateId>0||activeStatus==1"
65 :rightText="form.creditCode" 65 :rightText="form.creditCode"
...@@ -96,7 +96,8 @@ ...@@ -96,7 +96,8 @@
96 </view> 96 </view>
97 </template> 97 </template>
98 </uni-list-item> 98 </uni-list-item>
99 99 <uni-list-item :rightText="form.companyName||'--'" title="营业执照名称"/>
100 <uni-list-item :rightText="form.creditCode||'--'" title="社会信用代码"/>
100 <uni-list-item clickable title="营业执照"> 101 <uni-list-item clickable title="营业执照">
101 <template v-slot:footer> 102 <template v-slot:footer>
102 <view v-if="form.businessLicenseArr&&form.businessLicenseArr?.length>0" class="frrr" 103 <view v-if="form.businessLicenseArr&&form.businessLicenseArr?.length>0" class="frrr"
......
...@@ -96,13 +96,21 @@ async function getList() { ...@@ -96,13 +96,21 @@ async function getList() {
96 return uni.showToast({title: '请输入考官编号', icon: 'none'}) 96 return uni.showToast({title: '请输入考官编号', icon: 'none'})
97 97
98 loading.value = true 98 loading.value = true
99 try {
99 const res = await api.getCoachList(queryParams.value) 100 const res = await api.getCoachList(queryParams.value)
100 infoList.value = res.rows 101 infoList.value = res.rows || []
101 total.value = res.total 102 total.value = res.total || 0
103 } catch (err) {
104 console.error('获取考官列表失败:', err)
105 infoList.value = []
106 total.value = 0
107 } finally {
102 loading.value = false 108 loading.value = false
109 }
103 110
111 // 空数组提示
104 if (infoList.value.length === 0) { 112 if (infoList.value.length === 0) {
105 uni.showToast({title: '请核实考官编号、有效期及归属地!', icon: 'none'}) 113 uni.showToast({title: '请核实考官编号、有效期及归属地', icon: 'none', duration: 2000})
106 } 114 }
107 } 115 }
108 116
...@@ -163,7 +171,8 @@ async function confirmAddExpireExaminer() { ...@@ -163,7 +171,8 @@ async function confirmAddExpireExaminer() {
163 uni.navigateBack({delta: 1}) 171 uni.navigateBack({delta: 1})
164 } catch (err) { 172 } catch (err) {
165 console.log(err) 173 console.log(err)
166 uni.showToast({title: '添加失败', icon: 'none'}) 174 const errMsg = err?.data?.msg || err?.msg || '添加失败'
175 uni.showToast({title: errMsg, icon: 'none', duration: 3000})
167 } finally { 176 } finally {
168 expirePopup.value.close() 177 expirePopup.value.close()
169 currentExpireItem.value = null 178 currentExpireItem.value = null
......
...@@ -18,10 +18,10 @@ ...@@ -18,10 +18,10 @@
18 <uni-forms-item label="机构名称" required> 18 <uni-forms-item label="机构名称" required>
19 <uni-easyinput v-model="form.name" :disabled="type" placeholder="机构名称" /></uni-forms-item> 19 <uni-easyinput v-model="form.name" :disabled="type" placeholder="机构名称" /></uni-forms-item>
20 20
21 <uni-forms-item label="所属省份" required> 21 <!-- <uni-forms-item label="所属省份" required>
22 <uni-data-select :clear="false" :disabled="type&&(belongProvinceId||belongProvinceId==0)" 22 <uni-data-select :clear="false" :disabled="type&&(belongProvinceId||belongProvinceId==0)"
23 v-model="form.belongProvinceId" :localdata="regionsList"></uni-data-select> 23 v-model="form.belongProvinceId" :localdata="regionsList"></uni-data-select>
24 </uni-forms-item> 24 </uni-forms-item> -->
25 <uni-forms-item label="社会信用代码" required> 25 <uni-forms-item label="社会信用代码" required>
26 <uni-easyinput v-model="form.creditCode" :disabled="type&&!!creditCode&&newResult" /> 26 <uni-easyinput v-model="form.creditCode" :disabled="type&&!!creditCode&&newResult" />
27 </uni-forms-item> 27 </uni-forms-item>
...@@ -43,13 +43,11 @@ ...@@ -43,13 +43,11 @@
43 <uni-forms-item label="法人证件号" required> 43 <uni-forms-item label="法人证件号" required>
44 <uni-easyinput v-model="form.legalIdcCode" /> 44 <uni-easyinput v-model="form.legalIdcCode" />
45 </uni-forms-item> 45 </uni-forms-item>
46 <uni-forms-item label="营业执照名称" required>
47 <uni-easyinput v-model="form.companyName" />
48 </uni-forms-item>
49 46
50 <uni-forms-item v-if="form.deptType==6&&activeStatus!= 0" label="是否申请考点" required> 47
48 <!-- <uni-forms-item v-if="form.deptType==6&&activeStatus!= 0" label="是否申请考点" required>
51 <uni-data-checkbox v-model="form.applyPoints" :localdata="yesno" /> 49 <uni-data-checkbox v-model="form.applyPoints" :localdata="yesno" />
52 </uni-forms-item> 50 </uni-forms-item> -->
53 51
54 <uni-forms-item label="法人身份证" required> 52 <uni-forms-item label="法人身份证" required>
55 <view class="imgArea"> 53 <view class="imgArea">
...@@ -63,11 +61,17 @@ ...@@ -63,11 +61,17 @@
63 </uni-file-picker> 61 </uni-file-picker>
64 </view> 62 </view>
65 </uni-forms-item> 63 </uni-forms-item>
64 <uni-forms-item label="营业执照名称" required>
65 <uni-easyinput v-model="form.companyName" />
66 </uni-forms-item>
66 <uni-forms-item label="营业执照" required> 67 <uni-forms-item label="营业执照" required>
67 <uni-file-picker limit="1" v-model="businessLicenseArr" file-extname="png,jpg,jpeg,pdf" 68 <uni-file-picker limit="1" v-model="businessLicenseArr" file-extname="png,jpg,jpeg,pdf"
68 file-mediatype="all" @select="selectFile" @delete="delSupplementFile"></uni-file-picker> 69 file-mediatype="all" @select="selectFile" @delete="delSupplementFile"></uni-file-picker>
69
70 </uni-forms-item> 70 </uni-forms-item>
71 <!-- <uni-forms-item label="社会信用代码" required>
72 <uni-file-picker limit="1" v-model="businessLicenseArr" file-extname="png,jpg,jpeg,pdf"
73 file-mediatype="all" @select="selectFile" @delete="delSupplementFile"></uni-file-picker>
74 </uni-forms-item> -->
71 <uni-forms-item label="机构照片" required> 75 <uni-forms-item label="机构照片" required>
72 <uni-file-picker v-model="picArrR" limit="3" mode="grid" file-mediatype="image" 76 <uni-file-picker v-model="picArrR" limit="3" mode="grid" file-mediatype="image"
73 @select="upPicArr" @delete="delpicArr"> 77 @select="upPicArr" @delete="delpicArr">
......
...@@ -240,6 +240,13 @@ ...@@ -240,6 +240,13 @@
240 "navigationBarTitleText": "我的订单", 240 "navigationBarTitleText": "我的订单",
241 "enablePullDownRefresh": false 241 "enablePullDownRefresh": false
242 } 242 }
243 },
244 {
245 "path": "certPreview",
246 "style": {
247 "navigationBarTitleText": "电子会员证",
248 "enablePullDownRefresh": false
249 }
243 } 250 }
244 ] 251 ]
245 }, 252 },
...@@ -876,6 +883,20 @@ ...@@ -876,6 +883,20 @@
876 "navigationBarTitleText": "考生信息", 883 "navigationBarTitleText": "考生信息",
877 "enablePullDownRefresh": false 884 "enablePullDownRefresh": false
878 } 885 }
886 },
887 {
888 "path": "settlementAudit",
889 "style": {
890 "navigationBarTitleText": "结算审核",
891 "enablePullDownRefresh": false
892 }
893 },
894 {
895 "path": "settlementView",
896 "style": {
897 "navigationBarTitleText": "结算详情",
898 "enablePullDownRefresh": false
899 }
879 } 900 }
880 ] 901 ]
881 }, { 902 }, {
......
...@@ -239,18 +239,23 @@ ...@@ -239,18 +239,23 @@
239 <image :src="config.baseUrl_api+'/fs/static/icon/2.png'"/> 239 <image :src="config.baseUrl_api+'/fs/static/icon/2.png'"/>
240 考试审核 240 考试审核
241 </view> 241 </view>
242 <view @click="goPath('/level/ztx/cert?type=1')">
243 <image :src="config.baseUrl_api+'/fs/static/icon/18.png'"/>
244 证书发布
245 </view>
246 <view @click="goPath('/level/ztx/mail')"> 242 <view @click="goPath('/level/ztx/mail')">
247 <image :src="config.baseUrl_api+'/fs/static/icon/3.png'"/> 243 <image :src="config.baseUrl_api+'/fs/static/icon/3.png'"/>
248 证书邮寄 244 证书邮寄
249 </view> 245 </view>
246 <view @click="goPath('/level/ztx/cert?type=1')">
247 <image :src="config.baseUrl_api+'/fs/static/icon/18.png'"/>
248 证书发布
249 </view>
250 <view @click="goPath('/personalVip/changeLevelAudit')"> 250 <view @click="goPath('/personalVip/changeLevelAudit')">
251 <image :src="config.baseUrl_api+'/fs/static/icon/26.png'"/> 251 <image :src="config.baseUrl_api+'/fs/static/icon/26.png'"/>
252 变更审核 252 变更审核
253 </view> 253 </view>
254 <view @click="goPath('/level/settlementAudit')">
255 <image :src="config.baseUrl_api+'/fs/static/icon/10.png'"/>
256 结算审核
257 </view>
258
254 <view @click="goPath('/personalVip/order?type=2')"> 259 <view @click="goPath('/personalVip/order?type=2')">
255 <image :src="config.baseUrl_api+'/fs/static/icon/6.png'"/> 260 <image :src="config.baseUrl_api+'/fs/static/icon/6.png'"/>
256 订单列表 261 订单列表
......
...@@ -284,7 +284,7 @@ ...@@ -284,7 +284,7 @@
284 getDetail() 284 getDetail()
285 getRegionsList() 285 getRegionsList()
286 286
287 getMyMemberCertUnitFeeApi() 287 // getMyMemberCertUnitFeeApi()
288 canUseDiscountApi() 288 canUseDiscountApi()
289 getZtxDiscountPolicyApi() 289 getZtxDiscountPolicyApi()
290 getMyStatusAPI() 290 getMyStatusAPI()
......
...@@ -176,7 +176,7 @@ ...@@ -176,7 +176,7 @@
176 // 审核 176 // 审核
177 function goApproval(item) { 177 function goApproval(item) {
178 uni.navigateTo({ 178 uni.navigateTo({
179 url: `/pages/rank/scoreAudit?ids=${item.examId}&pageType=2` 179 url: `/pages/rank/scoreAudit?ids=${item.examId}&pageType=1`
180 }) 180 })
181 } 181 }
182 </script> 182 </script>
......
...@@ -87,12 +87,16 @@ ...@@ -87,12 +87,16 @@
87 delete params.reason 87 delete params.reason
88 } 88 }
89 89
90
90 try { 91 try {
91 // 根据 pageType 自动切换接口 92 // 根据 pageType 1 审核考试 2 审核成绩 3 结算审核
92 if (pageType.value == '1') { 93 if (pageType.value == '1') {
93 await api.auditDuanExam(params); 94 await api.auditDuanExam(params);
94 } else if (pageType.value == '2') { 95 } else if (pageType.value == '2') {
95 await api.auditDuanScore(params); 96 await api.auditDuanScore(params);
97 } else if (pageType.value == '3') {
98 params.type = '1' // 结算审核固定 type = 1
99 await api.settlementAudit(params);
96 } else { 100 } else {
97 uni.showToast({ title: '页面类型错误', icon: 'none' }); 101 uni.showToast({ title: '页面类型错误', icon: 'none' });
98 submitting.value = false; 102 submitting.value = false;
......
...@@ -51,6 +51,14 @@ ...@@ -51,6 +51,14 @@
51 <uni-easyinput :styles="inputstyle" :placeholderStyle="placeholderStyle" 51 <uni-easyinput :styles="inputstyle" :placeholderStyle="placeholderStyle"
52 v-model="baseFormData.phone" placeholder="请输入联系方式" /> 52 v-model="baseFormData.phone" placeholder="请输入联系方式" />
53 </uni-forms-item> 53 </uni-forms-item>
54 <uni-forms-item label="会员编号" name="perCode" v-if="baseFormData.perCode">
55 <uni-easyinput :styles="inputstyle" :placeholderStyle="placeholderStyle"
56 v-model="baseFormData.perCode" placeholder="请输入会员编号" />
57 </uni-forms-item>
58 <uni-forms-item label="会员有效期" name="validityDate" v-if="baseFormData.validityDate">
59 <uni-easyinput :styles="inputstyle" :placeholderStyle="placeholderStyle"
60 v-model="baseFormData.validityDate" placeholder="请输入会员有效期" />
61 </uni-forms-item>
54 62
55 63
56 <!-- <uni-forms-item label="所在地区"> 64 <!-- <uni-forms-item label="所在地区">
...@@ -148,6 +156,8 @@ ...@@ -148,6 +156,8 @@
148 sex: '', 156 sex: '',
149 idcType: '0', 157 idcType: '0',
150 perType: '1', // (1:个人会员;2:教练;3:考官;4:裁判;5:临时会员;) 158 perType: '1', // (1:个人会员;2:教练;3:考官;4:裁判;5:临时会员;)
159 perCode:'',
160 validityDate:''
151 }) 161 })
152 const items = ref(['身份证添加', '证件照录入']) 162 const items = ref(['身份证添加', '证件照录入'])
153 const idcTypeList = ref([{ 163 const idcTypeList = ref([{
...@@ -199,7 +209,7 @@ ...@@ -199,7 +209,7 @@
199 height: '316rpx' 209 height: '316rpx'
200 }); 210 });
201 211
202 onLoad((option) => { 212 onLoad(async (option) => {
203 if (option.tab == '1') { 213 if (option.tab == '1') {
204 current.value = 1 214 current.value = 1
205 baseFormData.value.sourceFlag = 1 215 baseFormData.value.sourceFlag = 1
...@@ -210,8 +220,11 @@ ...@@ -210,8 +220,11 @@
210 disabledName.value = true 220 disabledName.value = true
211 } 221 }
212 } 222 }
213 // console.log(current.value,option.tab) 223 // 如果传入了 perId,预填会员信息
214 // getRegionsList() 224 if (option.perId) {
225 perId.value = option.perId
226 await fetchMemberInfo(option.perId)
227 }
215 }) 228 })
216 229
217 onMounted(() => { 230 onMounted(() => {
...@@ -227,6 +240,40 @@ ...@@ -227,6 +240,40 @@
227 }) 240 })
228 } 241 }
229 242
243 // 根据 perId 获取会员信息预填表单
244 async function fetchMemberInfo(id) {
245 if (!id) return
246 uni.showLoading({ title: '加载中...' })
247 try {
248 const res = await api.getInfo(id)
249 const data = res.data || {}
250 baseFormData.value.name = data.name || ''
251 baseFormData.value.idcCode = data.idcCode || ''
252 baseFormData.value.idcType = data.idcType || '0'
253 baseFormData.value.sex = data.sex || ''
254 baseFormData.value.birth = data.birth || ''
255 baseFormData.value.phone = data.phone || ''
256 baseFormData.value.perCode = data.perCode || ''
257 baseFormData.value.validityDate = data.validityDate ? data.validityDate.slice(0, 10) : ''
258 // 照片处理
259 if (data.photo2) {
260 const photoUrl = data.photo2.indexOf('http') === -1 ? config.baseUrl_api + data.photo2 : data.photo2
261 photoArr.value = {
262 url: photoUrl,
263 name: '头像',
264 extname: 'jpg'
265 }
266 baseFormData.value.photo = data.photo
267 baseFormData.value.photo2 = data.photo2
268 }
269 disabledName.value = true
270 } catch (e) {
271 console.error('获取会员信息失败', e)
272 } finally {
273 uni.hideLoading()
274 }
275 }
276
230 function onClickItem(e) { 277 function onClickItem(e) {
231 if (current.value != e.currentIndex) { 278 if (current.value != e.currentIndex) {
232 current.value = e.currentIndex 279 current.value = e.currentIndex
...@@ -277,6 +324,8 @@ ...@@ -277,6 +324,8 @@
277 baseFormData.value.idcCode = res.data.code 324 baseFormData.value.idcCode = res.data.code
278 baseFormData.value.name = res.data.name 325 baseFormData.value.name = res.data.name
279 baseFormData.value.uuid = res.data.uuid 326 baseFormData.value.uuid = res.data.uuid
327 baseFormData.value.perCode = res.data.perCode ||''
328 baseFormData.value.validityDate = res.data.validityDate?.slice(0,10) //去掉时分秒
280 // baseFormData.value.cityId = res.data.cityId 329 // baseFormData.value.cityId = res.data.cityId
281 // baseFormData.value.address = res.data.address 330 // baseFormData.value.address = res.data.address
282 } else { 331 } else {
...@@ -363,6 +412,8 @@ ...@@ -363,6 +412,8 @@
363 baseFormData.value.birth = res.data.birth 412 baseFormData.value.birth = res.data.birth
364 baseFormData.value.name = res.data.name 413 baseFormData.value.name = res.data.name
365 baseFormData.value.phone = res.data.phone 414 baseFormData.value.phone = res.data.phone
415 baseFormData.value.perCode = res.data.perCode ||''
416 baseFormData.value.validityDate = res.data.validityDate?.slice(0,10) //去掉时分秒
366 // baseFormData.value.cityId = res.data.cityId 417 // baseFormData.value.cityId = res.data.cityId
367 // baseFormData.value.address = res.data.address 418 // baseFormData.value.address = res.data.address
368 if (res.data.photo) { 419 if (res.data.photo) {
......
1 <template>
2 <view class="preview-container">
3 <view class="loading-tip" v-if="loading">加载中...</view>
4 <view class="error-tip" v-else-if="showError">{{ errorMsg }}</view>
5
6 <view class="download-btn" @click="openDocument">
7 <text>查看会员证</text>
8 </view>
9 </view>
10 </template>
11
12 <script setup>
13 import { ref } from "vue";
14 import { onLoad } from "@dcloudio/uni-app";
15 import config from "@/config.js";
16
17 const pdfUrl = ref("");
18 const loading = ref(true);
19 const showError = ref(false);
20 const errorMsg = ref("");
21 const tempFilePath = ref("");
22
23 onLoad(async (option) => {
24 if (option.url) {
25 pdfUrl.value = config.baseUrl_api + decodeURIComponent(option.url);
26 await downloadPdf();
27 }
28 });
29
30 const downloadPdf = () => {
31 return new Promise((resolve) => {
32 uni.showLoading({ title: "加载中..." });
33 uni.downloadFile({
34 url: pdfUrl.value,
35 success: (res) => {
36 uni.hideLoading();
37 if (res.statusCode === 200) {
38 tempFilePath.value = res.tempFilePath;
39 loading.value = false;
40 // 自动打开文档
41 openDocument();
42 } else {
43 showError.value = true;
44 errorMsg.value = "下载失败";
45 }
46 resolve();
47 },
48 fail: () => {
49 uni.hideLoading();
50 showError.value = true;
51 errorMsg.value = "下载失败";
52 resolve();
53 }
54 });
55 });
56 };
57
58 const openDocument = () => {
59 if (!tempFilePath.value) {
60 uni.showToast({ title: "文件未准备好", icon: "none" });
61 return;
62 }
63 uni.openDocument({
64 filePath: tempFilePath.value,
65 fileType: "pdf",
66 showMenu: true,
67 success: () => {
68 console.log("打开文档成功");
69 },
70 fail: () => {
71 uni.showToast({ title: "打开失败,请在右上角菜单中下载", icon: "none" });
72 }
73 });
74 };
75 </script>
76
77 <style lang="scss" scoped>
78 .preview-container {
79 min-height: 100vh;
80 background: #f5f5f5;
81 position: relative;
82 }
83
84 .loading-tip {
85 position: absolute;
86 top: 50%;
87 left: 50%;
88 transform: translate(-50%, -50%);
89 font-size: 28rpx;
90 color: #666;
91 }
92
93 .error-tip {
94 position: absolute;
95 top: 50%;
96 left: 50%;
97 transform: translate(-50%, -50%);
98 font-size: 28rpx;
99 color: #C40F18;
100 }
101
102 .download-btn {
103 position: fixed;
104 bottom: 50rpx;
105 left: 50%;
106 transform: translateX(-50%);
107 background: #C40F18;
108 color: #fff;
109 padding: 24rpx 60rpx;
110 border-radius: 40rpx;
111 font-size: 28rpx;
112 z-index: 100;
113 }
114 </style>
...@@ -7,7 +7,7 @@ ...@@ -7,7 +7,7 @@
7 7
8 <!-- 绑定/解绑学员 --> 8 <!-- 绑定/解绑学员 -->
9 <view class="bind-student" @click="handleBindAction"> 9 <view class="bind-student" @click="handleBindAction">
10 <text>{{ isBound ? '解绑学员' : '绑定学员' }}</text> 10 <text>{{ isBound ? '切换学员' : '绑定学员' }}</text>
11 <image :src="config.baseUrl_api + '/fs/static/bd@2x.png'" class="bind-icon" mode="aspectFit"></image> 11 <image :src="config.baseUrl_api + '/fs/static/bd@2x.png'" class="bind-icon" mode="aspectFit"></image>
12 </view> 12 </view>
13 13
...@@ -22,7 +22,7 @@ ...@@ -22,7 +22,7 @@
22 mode="aspectFill"> 22 mode="aspectFill">
23 </image> 23 </image>
24 </view> 24 </view>
25 <view class="member-id">注册会员{{ userInfo.userName }}</view> 25 <view class="member-id">{{ userInfo.userName }}</view>
26 </view> 26 </view>
27 <view class="user-bottom"> 27 <view class="user-bottom">
28 <view class="user-name">{{ perInfo?.perName }}</view> 28 <view class="user-name">{{ perInfo?.perName }}</view>
...@@ -37,6 +37,16 @@ ...@@ -37,6 +37,16 @@
37 <image v-if="perInfo?.perValidDateFlag == 0" class="expired-stamp" 37 <image v-if="perInfo?.perValidDateFlag == 0" class="expired-stamp"
38 :src="config.baseUrl_api + '/fs/static/end@2x.png'" mode="aspectFit"> 38 :src="config.baseUrl_api + '/fs/static/end@2x.png'" mode="aspectFit">
39 </image> 39 </image>
40
41 <!-- 卡片右下角按钮 -->
42 <view class="card-btns">
43 <view class="card-btn" @click="goToPay">
44 <text>缴费</text>
45 </view>
46 <view class="card-btn" @click="downCert">
47 <text>电子会员证</text>
48 </view>
49 </view>
40 </view> 50 </view>
41 51
42 <!-- 功能按钮卡片 --> 52 <!-- 功能按钮卡片 -->
...@@ -56,7 +66,7 @@ ...@@ -56,7 +66,7 @@
56 </view> 66 </view>
57 <text class="func-text">个人会员</text> 67 <text class="func-text">个人会员</text>
58 </view> 68 </view>
59 <view class="func-item" @click="goToRecord"> 69 <view class="func-item" @click="goToRecord(0)">
60 <view class="func-icon"> 70 <view class="func-icon">
61 <image :src="config.baseUrl_api + '/fs/static/btn03@2x.png'"></image> 71 <image :src="config.baseUrl_api + '/fs/static/btn03@2x.png'"></image>
62 <!-- <uni-icons type="list" size="40" color="#1E88E5"></uni-icons> --> 72 <!-- <uni-icons type="list" size="40" color="#1E88E5"></uni-icons> -->
...@@ -75,7 +85,7 @@ ...@@ -75,7 +85,7 @@
75 </view> 85 </view>
76 <uni-icons type="arrowright" size="20" color="#999"></uni-icons> 86 <uni-icons type="arrowright" size="20" color="#999"></uni-icons>
77 </view> 87 </view>
78 <view class="query-item" @click="goToWebView(1)"> 88 <!-- <view class="query-item" @click="goToWebView(1)">
79 <view class="query-item-left"> 89 <view class="query-item-left">
80 <image :src="config.baseUrl_api + '/fs/static/user_icon03@2x.png'" class="query-item-icon"></image> 90 <image :src="config.baseUrl_api + '/fs/static/user_icon03@2x.png'" class="query-item-icon"></image>
81 <text class="query-item-text">单位会员查询</text> 91 <text class="query-item-text">单位会员查询</text>
...@@ -95,7 +105,7 @@ ...@@ -95,7 +105,7 @@
95 <text class="query-item-text">旧版级位证书查询</text> 105 <text class="query-item-text">旧版级位证书查询</text>
96 </view> 106 </view>
97 <uni-icons type="arrowright" size="20" color="#999"></uni-icons> 107 <uni-icons type="arrowright" size="20" color="#999"></uni-icons>
98 </view> 108 </view> -->
99 <view class="query-item" @click="goToWebView(4)"> 109 <view class="query-item" @click="goToWebView(4)">
100 <view class="query-item-left"> 110 <view class="query-item-left">
101 <image :src="config.baseUrl_api + '/fs/static/user_icon02@2x.png'" class="query-item-icon"></image> 111 <image :src="config.baseUrl_api + '/fs/static/user_icon02@2x.png'" class="query-item-icon"></image>
...@@ -103,59 +113,59 @@ ...@@ -103,59 +113,59 @@
103 </view> 113 </view>
104 <uni-icons type="arrowright" size="20" color="#999"></uni-icons> 114 <uni-icons type="arrowright" size="20" color="#999"></uni-icons>
105 </view> 115 </view>
106 <view class="query-item" @click="goToWebView(5)"> 116 <!-- <view class="query-item" @click="goToWebView(5)">
107 <view class="query-item-left"> 117 <view class="query-item-left">
108 <image :src="config.baseUrl_api + '/fs/static/user_icon02@2x.png'" class="query-item-icon"></image> 118 <image :src="config.baseUrl_api + '/fs/static/user_icon02@2x.png'" class="query-item-icon"></image>
109 <text class="query-item-text">级位记录查询</text> 119 <text class="query-item-text">级位记录查询</text>
110 </view> 120 </view>
111 <uni-icons type="arrowright" size="20" color="#999"></uni-icons> 121 <uni-icons type="arrowright" size="20" color="#999"></uni-icons>
112 </view> 122 </view> -->
113 <view class="query-item" @click="goToWebView(6)"> 123 <!-- <view class="query-item" @click="goToWebView(6)">
114 <view class="query-item-left"> 124 <view class="query-item-left">
115 <image :src="config.baseUrl_api + '/fs/static/user_icon02@2x.png'" class="query-item-icon"></image> 125 <image :src="config.baseUrl_api + '/fs/static/user_icon02@2x.png'" class="query-item-icon"></image>
116 <text class="query-item-text">国际段位证书查询</text> 126 <text class="query-item-text">国际段位证书查询</text>
117 </view> 127 </view>
118 <uni-icons type="arrowright" size="20" color="#999"></uni-icons> 128 <uni-icons type="arrowright" size="20" color="#999"></uni-icons>
119 </view> 129 </view> -->
120 <view class="query-item" @click="goToWebView(7)"> 130 <view class="query-item" @click="goToRecord(1)">
121 <view class="query-item-left"> 131 <view class="query-item-left">
122 <image :src="config.baseUrl_api + '/fs/static/user_icon02@2x.png'" class="query-item-icon"></image> 132 <image :src="config.baseUrl_api + '/fs/static/user_icon02@2x.png'" class="query-item-icon"></image>
123 <text class="query-item-text">中国段位证书查询</text> 133 <text class="query-item-text">我的段位</text>
124 </view> 134 </view>
125 <uni-icons type="arrowright" size="20" color="#999"></uni-icons> 135 <uni-icons type="arrowright" size="20" color="#999"></uni-icons>
126 </view> 136 </view>
127 <view class="query-item" @click="goToWebView(8)"> 137 <view class="query-item" @click="goToWebView(8)">
128 <view class="query-item-left"> 138 <view class="query-item-left">
129 <image :src="config.baseUrl_api + '/fs/static/user_icon03@2x.png'" class="query-item-icon"></image> 139 <image :src="config.baseUrl_api + '/fs/static/user_icon03@2x.png'" class="query-item-icon"></image>
130 <text class="query-item-text">级位考官查询</text> 140 <text class="query-item-text">级位考官</text>
131 </view> 141 </view>
132 <uni-icons type="arrowright" size="20" color="#999"></uni-icons> 142 <uni-icons type="arrowright" size="20" color="#999"></uni-icons>
133 </view> 143 </view>
134 <view class="query-item" @click="goToWebView(9)"> 144 <view class="query-item" @click="goToWebView(9)">
135 <view class="query-item-left"> 145 <view class="query-item-left">
136 <image :src="config.baseUrl_api + '/fs/static/user_icon03@2x.png'" class="query-item-icon"></image> 146 <image :src="config.baseUrl_api + '/fs/static/user_icon03@2x.png'" class="query-item-icon"></image>
137 <text class="query-item-text">段位考官查询</text> 147 <text class="query-item-text">段位考官</text>
138 </view> 148 </view>
139 <uni-icons type="arrowright" size="20" color="#999"></uni-icons> 149 <uni-icons type="arrowright" size="20" color="#999"></uni-icons>
140 </view> 150 </view>
141 <view class="query-item" @click="goToWebView(10)"> 151 <view class="query-item" @click="goToWebView(10)">
142 <view class="query-item-left"> 152 <view class="query-item-left">
143 <image :src="config.baseUrl_api + '/fs/static/user_icon03@2x.png'" class="query-item-icon"></image> 153 <image :src="config.baseUrl_api + '/fs/static/user_icon03@2x.png'" class="query-item-icon"></image>
144 <text class="query-item-text">大众教练员查询</text> 154 <text class="query-item-text">大众教练员</text>
145 </view> 155 </view>
146 <uni-icons type="arrowright" size="20" color="#999"></uni-icons> 156 <uni-icons type="arrowright" size="20" color="#999"></uni-icons>
147 </view> 157 </view>
148 <view class="query-item" @click="goToWebView(11)"> 158 <view class="query-item" @click="goToWebView(11)">
149 <view class="query-item-left"> 159 <view class="query-item-left">
150 <image :src="config.baseUrl_api + '/fs/static/user_icon03@2x.png'" class="query-item-icon"></image> 160 <image :src="config.baseUrl_api + '/fs/static/user_icon03@2x.png'" class="query-item-icon"></image>
151 <text class="query-item-text">大众裁判员查询</text> 161 <text class="query-item-text">大众裁判员</text>
152 </view> 162 </view>
153 <uni-icons type="arrowright" size="20" color="#999"></uni-icons> 163 <uni-icons type="arrowright" size="20" color="#999"></uni-icons>
154 </view> 164 </view>
155 <view class="query-item" @click="goToWebView(12)"> 165 <view class="query-item" @click="goToWebView(12)">
156 <view class="query-item-left"> 166 <view class="query-item-left">
157 <image :src="config.baseUrl_api + '/fs/static/user_icon03@2x.png'" class="query-item-icon"></image> 167 <image :src="config.baseUrl_api + '/fs/static/user_icon03@2x.png'" class="query-item-icon"></image>
158 <text class="query-item-text">培训讲师查询</text> 168 <text class="query-item-text">培训讲师</text>
159 </view> 169 </view>
160 <uni-icons type="arrowright" size="20" color="#999"></uni-icons> 170 <uni-icons type="arrowright" size="20" color="#999"></uni-icons>
161 </view> 171 </view>
...@@ -223,7 +233,8 @@ ...@@ -223,7 +233,8 @@
223 import to from 'await-to-js' 233 import to from 'await-to-js'
224 import { 234 import {
225 bindUser, 235 bindUser,
226 unbindUser 236 unbindUser,
237 downStuCertSingle
227 } from '@/common/api.js' 238 } from '@/common/api.js'
228 239
229 const userStore = useUserStore() 240 const userStore = useUserStore()
...@@ -232,10 +243,10 @@ ...@@ -232,10 +243,10 @@
232 console.log(222,userInfo.value) 243 console.log(222,userInfo.value)
233 console.log(333,perInfo.value) 244 console.log(333,perInfo.value)
234 245
235 // 是否已绑定学员 246 // 是否已绑定学员(根据会员卡号判断)
236 const isBound = computed(() => { 247 const isBound = computed(() => {
237 const perId = userInfo.value?.perId 248 const perCode = perInfo.value?.perCode
238 return perId !== undefined && perId !== null && perId !== 0 249 return perCode !== undefined && perCode !== null && perCode !== ''
239 }) 250 })
240 251
241 const bindPopup = ref(null) 252 const bindPopup = ref(null)
...@@ -252,8 +263,8 @@ const showConfirm = ref(false) ...@@ -252,8 +263,8 @@ const showConfirm = ref(false)
252 } 263 }
253 }) 264 })
254 265
255 watch(() => userInfo.value.perId, (val) => { 266 watch(() => perInfo.value?.perCode, (val) => {
256 if (val !== undefined && val == 0) { 267 if (val === undefined || val === null || val === '') {
257 nextTick(() => { 268 nextTick(() => {
258 openBindPopup() 269 openBindPopup()
259 }) 270 })
...@@ -282,14 +293,10 @@ const showConfirm = ref(false) ...@@ -282,14 +293,10 @@ const showConfirm = ref(false)
282 bindPopup.value?.close() 293 bindPopup.value?.close()
283 } 294 }
284 295
285 // 处理绑定/解绑操作 296 // 处理绑定/切换操作
286 const handleBindAction = () => { 297 const handleBindAction = async () => {
287 if (isBound.value) { 298 if (isBound.value) {
288 // 已绑定,执行解绑 299 // 已绑定,先解绑再打开绑定弹框
289 uni.showModal({
290 content: '确认解绑吗?',
291 success: async (res) => {
292 if (res.confirm) {
293 uni.showLoading({ 300 uni.showLoading({
294 title: '解绑中...', 301 title: '解绑中...',
295 mask: true 302 mask: true
...@@ -297,15 +304,8 @@ const showConfirm = ref(false) ...@@ -297,15 +304,8 @@ const showConfirm = ref(false)
297 const [err] = await to(unbindUser()) 304 const [err] = await to(unbindUser())
298 uni.hideLoading() 305 uni.hideLoading()
299 if (err) return 306 if (err) return
300 uni.showToast({
301 title: '解绑成功',
302 icon: 'success'
303 })
304 // 刷新用户信息
305 getWebInfo() 307 getWebInfo()
306 } 308 openBindPopup()
307 }
308 })
309 } else { 309 } else {
310 // 未绑定,打开绑定弹框 310 // 未绑定,打开绑定弹框
311 openBindPopup() 311 openBindPopup()
...@@ -341,9 +341,13 @@ const showConfirm = ref(false) ...@@ -341,9 +341,13 @@ const showConfirm = ref(false)
341 uni.hideLoading() 341 uni.hideLoading()
342 342
343 if (err) { 343 if (err) {
344 uni.showToast({
345 title: err?.data?.msg || err?.message || '绑定失败,请稍后重试',
346 icon: 'none',
347 duration: 3000
348 })
344 return 349 return
345 } 350 }else{
346
347 uni.showToast({ 351 uni.showToast({
348 title: '绑定成功', 352 title: '绑定成功',
349 icon: 'success' 353 icon: 'success'
...@@ -352,18 +356,33 @@ const showConfirm = ref(false) ...@@ -352,18 +356,33 @@ const showConfirm = ref(false)
352 getWebInfo() 356 getWebInfo()
353 } 357 }
354 358
359 // uni.showToast({
360 // title: '绑定成功',
361 // icon: 'success'
362 // })
363
364 }
365
355 // 返回上一页 366 // 返回上一页
356 const goBack = () => { 367 const goBack = () => {
357 uni.navigateBack() 368 uni.navigateBack()
358 } 369 }
359 370
360 const goToAuth = () => { 371 const goToAuth = () => {
372 if (!isBound.value) {
373 uni.showToast({ title: '请先绑定学员', icon: 'none' })
374 return
375 }
361 uni.navigateTo({ 376 uni.navigateTo({
362 url: '/personal/personInfo' 377 url: '/personal/personInfo'
363 }); 378 });
364 }; 379 };
365 380
366 const goToScore = () => { 381 const goToScore = () => {
382 if (!isBound.value) {
383 uni.showToast({ title: '请先绑定学员', icon: 'none' })
384 return
385 }
367 uni.navigateTo({ 386 uni.navigateTo({
368 url: '/personal/memberInfo' 387 url: '/personal/memberInfo'
369 }); 388 });
...@@ -371,26 +390,67 @@ const showConfirm = ref(false) ...@@ -371,26 +390,67 @@ const showConfirm = ref(false)
371 390
372 const goToWebView = (type) => { 391 const goToWebView = (type) => {
373 // const url = "https://member.taekwondo.org.cn/#/authAccurate?type=" + type 392 // const url = "https://member.taekwondo.org.cn/#/authAccurate?type=" + type
374 const url = "http://tk001.wxjylt.com/pc.html#/authAccurate?type=" + type 393 const url = "https://tk001.wxjylt.com/pc.html#/authAccurate?type=" + type
375 uni.navigateTo({ 394 uni.navigateTo({
376 url: "/pages/webview/webview?url=" + encodeURIComponent(url) 395 url: "/pages/webview/webview?url=" + encodeURIComponent(url)
377 }); 396 });
378 }; 397 };
379 398
380 // 导航到级位记录 399 // 导航到级位记录
381 const goToRecord = () => { 400 const goToRecord = (type) => {
401 if (!isBound.value) {
402 uni.showToast({ title: '请先绑定学员', icon: 'none' })
403 return
404 }
382 uni.navigateTo({ 405 uni.navigateTo({
383 url: '/personal/levelRecord' 406 url: '/personal/levelRecord?type=' + type
384 }); 407 });
385 }; 408 };
386 409
387 // 导航到我的订单 410 // 导航到我的订单
388 const goToOrder = () => { 411 const goToOrder = () => {
412 if (!isBound.value) {
413 uni.showToast({ title: '请先绑定学员', icon: 'none' })
414 return
415 }
389 uni.navigateTo({ 416 uni.navigateTo({
390 url: '/personal/order' 417 url: '/personal/order'
391 }); 418 });
392 }; 419 };
393 420
421 // 导航到缴费
422 const goToPay = () => {
423 const perId = userInfo.value?.perId
424 uni.navigateTo({
425 url: `/personal/addVip_per?perId=${perId}`
426 });
427 };
428
429 // 下载电子会员证
430 const downCert = async () => {
431 if (!isBound.value) {
432 uni.showToast({ title: '请先绑定学员', icon: 'none' })
433 return
434 }
435 const perId = userInfo.value?.perId
436 if (!perId) return
437
438 uni.showLoading({ title: '加载中...', mask: true })
439 const [err, res] = await to(downStuCertSingle(perId))
440 uni.hideLoading()
441
442 if (err) {
443 uni.showToast({ title: err?.data?.msg || '获取会员证失败', icon: 'none' })
444 return
445 }
446 const pdfUrl = res?.data
447 if (pdfUrl) {
448 uni.navigateTo({
449 url: `/personal/certPreview?url=${encodeURIComponent(pdfUrl)}`
450 })
451 }
452 };
453
394 454
395 455
396 // 显示退出登录确认框 456 // 显示退出登录确认框
...@@ -549,12 +609,33 @@ const showConfirm = ref(false) ...@@ -549,12 +609,33 @@ const showConfirm = ref(false)
549 .expired-stamp { 609 .expired-stamp {
550 position: absolute; 610 position: absolute;
551 right: 30rpx; 611 right: 30rpx;
552 bottom: 100rpx; 612 bottom: 150rpx;
553 width: 150rpx; 613 width: 150rpx;
554 height: 150rpx; 614 height: 150rpx;
555 z-index: 1; 615 z-index: 1;
556 } 616 }
557 617
618 /* 卡片右下角按钮 */
619 .card-btns {
620 position: absolute;
621 right: 30rpx;
622 bottom: 73rpx;
623 z-index: 10;
624 display: flex;
625 gap: 16rpx;
626 }
627
628 .card-btn {
629 // background: rgba(255, 255, 255, 0.9);
630 border-radius: 30rpx;
631 padding: 12rpx 20rpx;
632 }
633
634 .card-btn text {
635 font-size: 24rpx;
636 color: #C40F18;
637 }
638
558 /* 功能按钮卡片 */ 639 /* 功能按钮卡片 */
559 .func-card { 640 .func-card {
560 margin: -70rpx 30rpx 30rpx; 641 margin: -70rpx 30rpx 30rpx;
......
...@@ -76,6 +76,8 @@ ...@@ -76,6 +76,8 @@
76 76
77 <script setup> 77 <script setup>
78 import { ref, onMounted } from 'vue'; 78 import { ref, onMounted } from 'vue';
79 import { onLoad } from '@dcloudio/uni-app';
80
79 import { useUserStore } from '../store/modules/user'; 81 import { useUserStore } from '../store/modules/user';
80 import { getAssoPers } from '@/common/api.js'; 82 import { getAssoPers } from '@/common/api.js';
81 import { getPersonTecDetails } from '@/common/api.js'; 83 import { getPersonTecDetails } from '@/common/api.js';
...@@ -90,12 +92,22 @@ ...@@ -90,12 +92,22 @@
90 // 变更记录相关 92 // 变更记录相关
91 const changeRecordPopup = ref(null); 93 const changeRecordPopup = ref(null);
92 const currentChangeRecord = ref(null); 94 const currentChangeRecord = ref(null);
95 const pageType = ref('');
93 96
94 // 返回上一页 97 // 返回上一页
95 const goBack = () => { 98 const goBack = () => {
96 uni.navigateBack(); 99 uni.navigateBack();
97 }; 100 };
98 101 onLoad((option) => {
102 if (option.type) {
103 pageType.value = option.type;
104 if (pageType.value == '0') {
105 uni.setNavigationBarTitle({ title: '级位记录' })
106 } else if (pageType.value == '1') {
107 uni.setNavigationBarTitle({ title: '段位记录' })
108 }
109 }
110 });
99 // 显示变更记录 111 // 显示变更记录
100 const showChangeRecord = (item) => { 112 const showChangeRecord = (item) => {
101 // remark已经在getLevelRecords中解析过了,直接使用 113 // remark已经在getLevelRecords中解析过了,直接使用
...@@ -116,7 +128,7 @@ ...@@ -116,7 +128,7 @@
116 const getLevelRecords = async () => { 128 const getLevelRecords = async () => {
117 loading.value = true; 129 loading.value = true;
118 try { 130 try {
119 const res = await getPersonTecDetails(0, perId.value); // 0表示级位 131 const res = await getPersonTecDetails(pageType.value, perId.value); // 0表示级位
120 levelRecords.value = res.data || []; 132 levelRecords.value = res.data || [];
121 // 处理数据 133 // 处理数据
122 levelRecords.value.forEach(item => { 134 levelRecords.value.forEach(item => {
......
...@@ -51,6 +51,14 @@ ...@@ -51,6 +51,14 @@
51 <uni-easyinput :styles="inputstyle" :placeholderStyle="placeholderStyle" 51 <uni-easyinput :styles="inputstyle" :placeholderStyle="placeholderStyle"
52 v-model="baseFormData.phone" placeholder="请输入联系方式" /> 52 v-model="baseFormData.phone" placeholder="请输入联系方式" />
53 </uni-forms-item> 53 </uni-forms-item>
54 <uni-forms-item label="会员编号" name="perCode" v-if="baseFormData.perCode">
55 <uni-easyinput :styles="inputstyle" :placeholderStyle="placeholderStyle"
56 v-model="baseFormData.perCode" placeholder="请输入会员编号" />
57 </uni-forms-item>
58 <uni-forms-item label="会员有效期" name="validityDate" v-if="baseFormData.validityDate">
59 <uni-easyinput :styles="inputstyle" :placeholderStyle="placeholderStyle"
60 v-model="baseFormData.validityDate" placeholder="请输入会员有效期" />
61 </uni-forms-item>
54 62
55 63
56 <uni-forms-item label="所在地区"> 64 <uni-forms-item label="所在地区">
...@@ -142,6 +150,8 @@ ...@@ -142,6 +150,8 @@
142 sex: '', 150 sex: '',
143 idcType: '0', 151 idcType: '0',
144 perType: '1', // (1:个人会员;2:教练;3:考官;4:裁判;5:临时会员;) 152 perType: '1', // (1:个人会员;2:教练;3:考官;4:裁判;5:临时会员;)
153 perCode:'',
154 validityDate:''
145 }) 155 })
146 const items = ref(['身份证添加', '证件照录入']) 156 const items = ref(['身份证添加', '证件照录入'])
147 const idcTypeList = ref([{ 157 const idcTypeList = ref([{
...@@ -356,6 +366,8 @@ ...@@ -356,6 +366,8 @@
356 baseFormData.value.phone = res.data.phone 366 baseFormData.value.phone = res.data.phone
357 baseFormData.value.cityId = res.data.cityId 367 baseFormData.value.cityId = res.data.cityId
358 baseFormData.value.address = res.data.address 368 baseFormData.value.address = res.data.address
369 baseFormData.value.perCode = res.data.perCode ||''
370 baseFormData.value.validityDate = res.data.validityDate?.slice(0,10) //去掉时分秒
359 if (res.data.photo) { 371 if (res.data.photo) {
360 console.log(res.data.photo) 372 console.log(res.data.photo)
361 if (res.data.photo.indexOf('http') == -1) { 373 if (res.data.photo.indexOf('http') == -1) {
......
...@@ -51,15 +51,15 @@ ...@@ -51,15 +51,15 @@
51 <view class="stats-row"> 51 <view class="stats-row">
52 <view class="stat-item"> 52 <view class="stat-item">
53 <text class="stat-label">人数合计</text> 53 <text class="stat-label">人数合计</text>
54 <text class="stat-value">{{ item.allCount || 0 }}</text> 54 <text class="stat-value">{{ item.allCount || '/' }}</text>
55 </view> 55 </view>
56 <view class="stat-item"> 56 <view class="stat-item">
57 <text class="stat-label">新会员合计</text> 57 <text class="stat-label">新会员合计</text>
58 <text class="stat-value">{{ item.newCount || 0 }}</text> 58 <text class="stat-value">{{ item.newCount || '/' }}</text>
59 </view> 59 </view>
60 <view class="stat-item"> 60 <view class="stat-item">
61 <text class="stat-label">年限合计</text> 61 <text class="stat-label">年限合计</text>
62 <text class="stat-value">{{ item.yearCount || 0 }}</text> 62 <text class="stat-value">{{ item.yearCount || '/' }}</text>
63 </view> 63 </view>
64 </view> 64 </view>
65 65
...@@ -493,7 +493,7 @@ onUnmounted(() => { ...@@ -493,7 +493,7 @@ onUnmounted(() => {
493 } 493 }
494 .stat-value { 494 .stat-value {
495 font-size:32rpx; 495 font-size:32rpx;
496 font-weight:700; 496 // font-weight:700;
497 color:#333; 497 color:#333;
498 } 498 }
499 } 499 }
......
Styling with Markdown is supported
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!