f527b6cd by 张猛

支付

1 parent 7caf72e2
......@@ -250,7 +250,8 @@ export function insertSinglePay(data) {
return request({
url: '/person/paymentNew/insertSinglePay',
method: 'post',
params: data
params: data,
showLoading: false
})
}
......@@ -1541,6 +1542,7 @@ export function certifiedNew(renewYear) {
return request({
url: `/system/certifiedNew/commit?renewYear=${renewYear}`,
method: 'post',
showLoading: false
})
}
......@@ -1629,7 +1631,8 @@ export function getMyStatus() {
export function goPay(id, payType) {
return request({
url: `/person/paymentRangeNew/pay/${id}/${payType}`,
method: 'post'
method: 'post',
showLoading: false
})
}
......@@ -1839,7 +1842,8 @@ export function commitJiExam(params) {
return request({
url: `/exam/info/commitJi/${params.id}/${params.addresId}/${params.payType}`,
method: 'post',
params
params,
showLoading: false
})
}
......
......@@ -31,6 +31,7 @@ async function minShengPay(orderId, encryptedData) {
title: '生成支付...',
mask: true
})
console.log(1111)
// 参数校验
if (!orderId) {
......@@ -219,7 +220,6 @@ function invokeWechatPayment(payParams, orderId) {
})
},
fail: async (err) => {
debugger
// 用户取消支付
if (err.errMsg?.includes('cancel')) {
await handleUserCancel(orderId)
......
// dev
// const baseUrl_api = 'http://192.168.1.137:8787'
const baseUrl_api = 'http://tk001.wxjylt.com/stage-api'
const baseUrl_api = 'http://192.168.1.137:8787'
// const baseUrl_api = 'http://tk001.wxjylt.com/stage-api'
const loginImage_api = 'http://tk001.wxjylt.com/stage-api'
const payUrl = 'https://wxpay.cmbc.com.cn/mobilePlatform/appserver/lcbpPay.do'
......
<template>
<view class="add-apply-page">
<!-- 顶部步骤条 -->
<view class="steps-bar">
<view class="step-item" :class="{ active: active >= 0, current: active == 0 }">
<view class="step-circle">1</view>
<view class="step-text">考级基本信息</view>
</view>
<view class="step-line" :class="{ active: active >= 1 }"></view>
<view class="step-item" :class="{ active: active >= 1, current: active == 1 }">
<view class="step-circle">2</view>
<view class="step-text">添加考生</view>
</view>
</view>
<view class="page-content">
<!-- 步骤1:考级基本信息 -->
<view class="wBox" v-if="active == 0">
<uni-forms ref="baseForm" :modelValue="form" label-width="100">
<uni-forms-item label="考试名称">
<view class="align-forms-item" v-if="form.name">{{form.name}}</view>
<view v-else class="align-forms-item-placeHolder">自动生成</view>
</uni-forms-item>
<uni-forms-item label="申请单位" required>
<view class="align-forms-item">{{form.memberName}}</view>
</uni-forms-item>
<uni-forms-item label="申请日期" required>
<uni-datetime-picker type="date" v-model="form.applyTime"></uni-datetime-picker>
</uni-forms-item>
<uni-forms-item label="考试开始时间" required>
<uni-datetime-picker type="datetime" v-model="form.startTime"></uni-datetime-picker>
</uni-forms-item>
<uni-forms-item label="考试结束时间" required>
<uni-datetime-picker type="datetime" v-model="form.endTime"></uni-datetime-picker>
</uni-forms-item>
<uni-forms-item label="考级地点" required>
<uni-easyinput v-model="form.examLocation" placeholder="考级地点" />
</uni-forms-item>
<uni-forms-item :label="`考官${ec}`" v-for="ec in examinerForChoose" :key="ec">
<view class="maskbox">
<view class="mask" @click="selectFN(ec)"></view>
<uni-easyinput v-model="form[`examiner_${ec}`]" clearable placeholder="点击选择考官" />
</view>
</uni-forms-item>
</uni-forms>
</view>
<!-- 步骤2:添加考生 -->
<view class="step2-content" v-if="active == 1">
<!-- 考级信息卡片 -->
<view class="exam-info-card">
<view class="card-header">
<text class="card-title">考级信息</text>
</view>
<view class="info-grid">
<view class="info-item">
<text class="info-label">考试名称</text>
<text class="info-value">{{form.name || '-'}}</text>
</view>
<view class="info-item">
<text class="info-label">申请单位</text>
<text class="info-value">{{form.memberName || '-'}}</text>
</view>
<view class="info-item">
<text class="info-label">考试地点</text>
<text class="info-value">{{form.examLocation || '-'}}</text>
</view>
<view class="info-item">
<text class="info-label">考试时间</text>
<text class="info-value">{{formatDateTime(form.startTime)}} - {{formatDateTime(form.endTime)}}</text>
</view>
</view>
</view>
<!-- 操作栏(红框顶部统计+添加按钮) -->
<button class="btn-add-student" @click="goChooseStudent">
<uni-icons type="plus" size="16" color="#fff"></uni-icons>
添加考生
</button>
<view class="action-bar">
<view class="stat-info">
<text class="stat-total">{{tablePersonInfo.total || 0}}</text>
<view class="level-tags">
<view class="level-tag" v-for="l in tablePersonInfo.levelArr" :key="l.level">
{{ szToHz(l.level) }}级:{{l.num}}
</view>
</view>
</view>
</view>
<!-- 考生列表(红框主体) -->
<view class="student-list">
<view class="student-card" v-for="(n,index) in infoList" :key="index">
<!-- 左侧:头像+考生信息 -->
<view class="card-left">
<view class="avatar">
<image v-if="n.photo" :src="n.photo" mode="aspectFill" />
<image v-else :src="config.baseUrl_api + '/fs/static/tx@2x.png'"
mode="aspectFill">
</image>
<!-- <text v-else class="avatar-text">{{(n.realName || '').slice(0,1)}}</text> -->
</view>
<view class="student-info">
<view class="student-name">{{n.realName}} <text class="per-code">{{n.perCode}}</text></view>
<view class="student-idcard">{{n.idcTypeStr}}{{n.idcCode}}</view>
</view>
</view>
<!-- 右侧:原级别/考试级别/是否通过 -->
<view class="card-right">
<view class="level-item">
<text class="level-label">原级别</text>
<text class="level-value">{{ szToHz(n.levelOld) }}</text>
</view>
<view class="level-item">
<text class="level-label">考试级别</text>
<view class="select-wrapper" @click="changeLevelfather(n)">
<uni-data-select v-model="n.levelNew" :localdata="levelArr" @change="changeLevel" :clear="false" />
</view>
</view>
<view class="level-item">
<text class="level-label">是否通过</text>
<view class="select-wrapper">
<uni-data-select v-model="n.isPass" :localdata="range" :clear="false" />
</view>
</view>
</view>
<!-- 删除按钮 -->
<view class="delete-btn" @click="handleDelete(n)">
<uni-icons type="trash" size="18" color="#dd524d"></uni-icons>
</view>
</view>
<!-- 空状态 -->
<view class="empty" v-if="infoList.length==0">
<image class="empty-img" mode="aspectFit" :src="config.baseUrl_api + '/fs/static/nodata.png'" />
<text class="empty-text">暂无考生信息</text>
</view>
</view>
</view>
</view>
<!-- 底部按钮 -->
<view class="fixedBottom" v-if="active == 0">
<button class="btn-red-kx" style="width: 40%;" @click="submitForm(0)">保存</button>
<button class="btn-red" style="width: 40%;" @click="submitForm(1)">下一步</button>
</view>
<view class="fixedBottom" v-if="active == 1">
<button class="btn-red-kx" style="width: 25%;" @click="prev">上一步</button>
<button class="btn-red-kx" style="width: 25%;" @click="submitForm2(0)">保存</button>
<button class="btn-red" style="width: 30%;" @click="submitForm2(1)">提交审核</button>
</view>
</view>
<view class="add-apply-page">
<!-- 顶部步骤条 -->
<view class="steps-bar">
<view :class="{ active: active >= 0, current: active == 0 }" class="step-item">
<view class="step-circle">1</view>
<view class="step-text">考级基本信息</view>
</view>
<view :class="{ active: active >= 1 }" class="step-line"></view>
<view :class="{ active: active >= 1, current: active == 1 }" class="step-item">
<view class="step-circle">2</view>
<view class="step-text">添加考生</view>
</view>
</view>
<view class="page-content">
<!-- 步骤1:考级基本信息 -->
<view v-if="active == 0" class="wBox">
<uni-forms ref="baseForm" :modelValue="form" label-width="100">
<uni-forms-item label="考试名称">
<view v-if="form.name" class="align-forms-item">{{ form.name }}</view>
<view v-else class="align-forms-item-placeHolder">自动生成</view>
</uni-forms-item>
<uni-forms-item label="申请单位" required>
<view class="align-forms-item">{{ form.memberName }}</view>
</uni-forms-item>
<uni-forms-item label="申请日期" required>
<uni-datetime-picker v-model="form.applyTime" type="date"></uni-datetime-picker>
</uni-forms-item>
<uni-forms-item label="考试开始时间" required>
<uni-datetime-picker v-model="form.startTime" type="datetime"></uni-datetime-picker>
</uni-forms-item>
<uni-forms-item label="考试结束时间" required>
<uni-datetime-picker v-model="form.endTime" type="datetime"></uni-datetime-picker>
</uni-forms-item>
<uni-forms-item label="考级地点" required>
<uni-easyinput v-model="form.examLocation" placeholder="考级地点"/>
</uni-forms-item>
<uni-forms-item v-for="ec in examinerForChoose" :key="ec" :label="`考官${ec}`">
<view class="maskbox">
<view class="mask" @click="selectFN(ec)"></view>
<uni-easyinput v-model="form[`examiner_${ec}`]" clearable placeholder="点击选择考官"/>
</view>
</uni-forms-item>
</uni-forms>
</view>
<!-- 步骤2:添加考生 -->
<view v-if="active == 1" class="step2-content">
<!-- 考级信息卡片 -->
<view class="exam-info-card">
<view class="card-header">
<text class="card-title">考级信息</text>
</view>
<view class="info-grid">
<view class="info-item">
<text class="info-label">考试名称</text>
<text class="info-value">{{ form.name || '-' }}</text>
</view>
<view class="info-item">
<text class="info-label">申请单位</text>
<text class="info-value">{{ form.memberName || '-' }}</text>
</view>
<view class="info-item">
<text class="info-label">考试地点</text>
<text class="info-value">{{ form.examLocation || '-' }}</text>
</view>
<view class="info-item">
<text class="info-label">考试时间</text>
<text class="info-value">{{ formatDateTime(form.startTime) }} - {{ formatDateTime(form.endTime) }}</text>
</view>
</view>
</view>
<!-- 操作栏(红框顶部统计+添加按钮) -->
<button class="btn-add-student" @click="goChooseStudent">
<uni-icons color="#fff" size="16" type="plus"></uni-icons>
添加考生
</button>
<view class="action-bar">
<view class="stat-info">
<text class="stat-total">{{ tablePersonInfo.total || 0 }}</text>
<view class="level-tags">
<view v-for="l in tablePersonInfo.levelArr" :key="l.level" class="level-tag">
{{ szToHz(l.level) }}级:{{ l.num }}
</view>
</view>
</view>
</view>
<!-- 考生列表(红框主体) -->
<view class="student-list">
<view v-for="(n,index) in infoList" :key="index" class="student-card">
<!-- 左侧:头像+考生信息 -->
<view class="card-left">
<view class="avatar">
<image v-if="n.photo" :src="n.photo" mode="aspectFill"/>
<image v-else :src="config.baseUrl_api + '/fs/static/tx@2x.png'"
mode="aspectFill">
</image>
<!-- <text v-else class="avatar-text">{{(n.realName || '').slice(0,1)}}</text> -->
</view>
<view class="student-info">
<view class="student-name">{{ n.realName }}
<text class="per-code">{{ n.perCode }}</text>
</view>
<view class="student-idcard">{{ n.idcTypeStr }}{{ n.idcCode }}</view>
</view>
</view>
<!-- 右侧:原级别/考试级别/是否通过 -->
<view class="card-right">
<view class="level-item">
<text class="level-label">原级别</text>
<text class="level-value">{{ szToHz(n.levelOld) }}</text>
</view>
<view class="level-item">
<text class="level-label">考试级别</text>
<view class="select-wrapper" @click="changeLevelfather(n)">
<uni-data-select v-model="n.levelNew" :clear="false" :localdata="levelArr" @change="changeLevel"/>
</view>
</view>
<view class="level-item">
<text class="level-label">是否通过</text>
<view class="select-wrapper">
<uni-data-select v-model="n.isPass" :clear="false" :localdata="range"/>
</view>
</view>
</view>
<!-- 删除按钮 -->
<view class="delete-btn" @click="handleDelete(n)">
<uni-icons color="#dd524d" size="18" type="trash"></uni-icons>
</view>
</view>
<!-- 空状态 -->
<view v-if="infoList.length==0" class="empty">
<image :src="config.baseUrl_api + '/fs/static/nodata.png'" class="empty-img" mode="aspectFit"/>
<text class="empty-text">暂无考生信息</text>
</view>
</view>
</view>
</view>
<!-- 底部按钮 -->
<view v-if="active == 0" class="fixedBottom">
<button class="btn-red-kx" style="width: 40%;" @click="submitForm(0)">保存</button>
<button class="btn-red" style="width: 40%;" @click="submitForm(1)">下一步</button>
</view>
<view v-if="active == 1" class="fixedBottom">
<button class="btn-red-kx" style="width: 25%;" @click="prev">上一步</button>
<button class="btn-red-kx" style="width: 25%;" @click="submitForm2(0)">保存</button>
<button class="btn-red" style="width: 30%;" @click="submitForm2(1)">提交审核</button>
</view>
</view>
</template>
<script setup>
import { ref } from 'vue';
import * as api from '@/common/api.js';
import { onLoad, onShow } from '@dcloudio/uni-app';
import config from '@/config.js'
import dayjs from 'dayjs'
import _ from 'underscore'
const app = getApp();
const memberInfo = app.globalData.memberInfo
const form = ref({
type: '1'
});
const examinerForChoose = ['A', 'B', 'C']
let examinerArr = []
const active = ref(0)
const infoList = ref([])
const tablePersonInfo = ref({})
const transcript = ref([]) // 补全缺失变量
const levelArr = ref([{
value: '10',
text: '十级'
}, {
value: '9',
text: '九级'
}, {
value: '8',
text: '八级'
}, {
value: '7',
text: '七级'
}, {
value: '6',
text: '六级'
}, {
value: '5',
text: '五级'
}, {
value: '4',
text: '四级'
}, {
value: '3',
text: '三级'
}, {
value: '2',
text: '二级'
}, {
value: '1',
text: '一级'
}])
const range = ref([{
value: '1',
text: '是'
}, {
value: '0',
text: '否'
}])
let examId
onLoad(option => {
if (app.globalData.isLogin) {
initData(option)
} else {
app.firstLoadCallback = () => {
initData(option)
};
}
});
function initData(option) {
form.value.memberName = app.globalData.memberInfo.name
form.value.applyTime = dayjs().format('YYYY-MM-DD')
_.each(examinerForChoose, ec => {
form.value[`examiner_${ec}`] = null
})
if (option.examId) {
examId = option.examId
// 如果是编辑模式,从URL参数获取active
if (option.step == '2') {
active.value = 1
getDetail()
getChosedStudentList()
} else {
getDetail()
}
}
}
onShow(() => {
uni.$on('chosen', updateData)
const curExamId = examId || form.value.examId
if (curExamId) {
getChosedStudentList()
}
})
function updateData(e) {
examinerArr.push(e.obj)
form.value[`examiner_${e.ec}`] = e.obj.name
}
function getDetail() {
api.getLevelApplyInfo(examId || form.value.examId).then(res => {
const data = res.data
if (data.examiner) {
_.each(data.examiner.split(','), (id, i) => {
examinerArr[i] = { perId: id }
})
_.each(data.examinerNames.split(','), (name, i) => {
data[`examiner_${examinerForChoose[i]}`] = name
if (examinerArr[i]) {
examinerArr[i].name = name
}
})
}
form.value = data
})
}
function selectFN(ec) {
const chosen = []
_.each(examinerForChoose, ecKey => {
const key = `examiner_${ecKey}`
if (form.value[key]) {
const examiner = _.find(examinerArr, (e) => {
return e.name == form.value[key]
})
if (examiner) {
chosen.push(examiner)
}
}
})
const arr = encodeURIComponent(JSON.stringify(chosen))
let path = `/level/chooseExaminer?type=${form.value.type}&chosen=${arr}&ec=${ec}`
uni.navigateTo({
url: path
});
}
function submitForm(flag) {
form.value.status = '0'
const examinerIds = []
const examinerNames = []
_.each(examinerForChoose, ec => {
const key = `examiner_${ec}`
if (form.value[key]) {
const examiner = _.find(examinerArr, (e) => {
return e.name == form.value[key]
})
if (examiner) {
examinerIds.push(examiner.perId)
examinerNames.push(examiner.name)
}
}
})
if (examinerIds.length > 0) {
form.value.examiner = examinerIds.join(',')
form.value.examinerNames = examinerNames.join(',')
} else {
form.value.examiner = null
form.value.examinerNames = null
}
// draftFlag: 0-保存 1-保存并下一步
form.value.draftFlag = flag === 0 ? '1' : '0'
if (flag === 0) {
// 仅保存
save()
} else {
// 保存并下一步 - 需校验
if (!form.value.applyTime) {
uni.showToast({ title: '请选择申请日期', icon: 'none' })
return
}
if (!form.value.startTime) {
uni.showToast({ title: '请选择考试开始时间', icon: 'none' })
return
}
if (!form.value.endTime) {
uni.showToast({ title: '请选择考试结束时间', icon: 'none' })
return
}
if (!form.value.examLocation) {
uni.showToast({ title: '请输入考级地点', icon: 'none' })
return
}
if (dayjs(form.value.startTime).valueOf() < dayjs(form.value.applyTime).valueOf()) {
uni.showToast({ title: '考试开始时间应大于申请日期', icon: 'none' })
return
}
if (dayjs(form.value.endTime).valueOf() <= dayjs(form.value.startTime).valueOf()) {
uni.showToast({ title: '考试结束时间应大于考试开始时间', icon: 'none' })
return
}
if (examinerIds.length % 2 === 0) {
uni.showToast({ title: '录入的考官人数必须为单数', icon: 'none' })
return
}
save().then(() => {
active.value = 1
getChosedStudentList()
if (form.value.examId) {
api.getLevelApplyInfo(form.value.examId).then(res => {
if (res.data.transcript) {
transcript.value = JSON.parse(res.data.transcript)
}
})
}
})
}
}
function save() {
if (form.value.examId) {
return api.updateLevelInfo(form.value).then(() => {
uni.showToast({ title: '保存成功', icon: 'none' })
})
} else {
return api.addLevelInfo(form.value).then((res) => {
form.value.examId = res.data.examId
form.value.name = res.data.name
uni.showToast({ title: '保存成功', icon: 'none' })
})
}
}
function prev() {
active.value = 0
}
function goChooseStudent() {
uni.navigateTo({
url: `/level/chooseStudent?examId=${form.value.examId}&memId=${memberInfo.memId}&examType=${form.value.type}`
})
}
// 格式化日期时间
function formatDateTime(dateStr) {
if (!dateStr) return '-'
return dateStr.substring(0, 10)
}
function getChosedStudentList() {
if (!form.value.examId) return
var obj = {
examId: form.value.examId
}
api.getStudentList(obj).then(res => {
_.each(res.rows, (d) => {
if (d.levelOld) {
d.levelRecommend = (parseInt(d.levelOld) - 1) + ''
if (d.levelRecommend === '0') {
d.levelRecommend = '1'
}
} else {
d.levelRecommend = '9'
}
if (!d.levelNew) {
d.levelNew = d.levelRecommend
}
if (!d.isPass) {
d.isPass = '1'
}
if (d.photo && d.photo.indexOf('http') == -1) {
d.photo = config.baseUrl_api + d.photo
}
})
infoList.value = res.rows
}).then(getTablePersonInfo)
}
function getTablePersonInfo() {
const total = infoList.value.length
const levelArrData = []
_.each(infoList.value, (d) => {
const temp = _.find(levelArrData, (l) => {
return l.level == d.levelNew
})
if (temp) {
temp.num++
} else {
levelArrData.push({
level: d.levelNew,
num: 1
})
}
})
tablePersonInfo.value = {
total: total,
levelArr: _.sortBy(levelArrData, (l) => {
return l.level
})
}
}
function szToHz(num) {
const hzArr = ['〇', '一', '二', '三', '四', '五', '六', '七', '八', '九', '十']
return hzArr[parseInt(num)]
}
let nowRow
function changeLevelfather(row) {
nowRow = row
api.jiDropDownBox({
perId: row.perId
}).then(res => {
levelArr.value = res.data
for (var l of levelArr.value) {
l.text = l.name
l.disabled = !(l.status)
}
})
}
function changeLevel(e) {
if (e == nowRow.levelOld) {
uni.showToast({ title: '考试级别重复,请重新选择!', icon: 'none' })
nowRow.levelNew = nowRow.levelRecommend
return
}
if (e !== nowRow.levelRecommend) {
uni.showModal({
title: '提示',
content: `建议考试级别为 "${szToHz(nowRow.levelRecommend)}级" ,确定要修改为${szToHz(e)}级吗?`,
success: function(res) {
if (res.confirm) {
getTablePersonInfo()
} else {
nowRow.levelNew = nowRow.levelRecommend
}
},
fail: function(res) {
nowRow.levelNew = nowRow.levelRecommend
}
})
}
}
function submitForm2(flag) {
// 循环校验考试级别
for (var item of infoList.value) {
if (item.levelNew == item.levelOld) {
uni.showToast({ title: `${item.realName}考试级别重复,请重新选择!`, icon: 'none' })
return
}
if (!item.levelNew) {
uni.showToast({ title: `${item.realName}请选择考试级别!`, icon: 'none' })
return
}
}
if (flag === 1) {
if (infoList.value.length == 0) {
uni.showToast({ title: '请选择考生', icon: 'none' })
return
}
uni.showModal({
title: '提示',
content: `请确认人员照片是否已更新?`,
success: function(res) {
if (res.confirm) {
saveStep2(flag).then(() => {
uni.showToast({ title: '提交成功', icon: 'none' })
uni.navigateTo({
url: `/level/paymentDetail?examId=${form.value.examId}`
})
})
}
}
})
} else {
saveStep2(flag).then(() => {
uni.showToast({ title: '操作成功', icon: 'none' })
})
}
}
function saveStep2(flag) {
const data = _.map(infoList.value, (d) => {
return {
id: d.id,
levelNew: d.levelNew,
isPass: d.isPass
}
})
return api.editLevel({
examId: form.value.examId,
personInfo: JSON.stringify(data),
transcript: form.value.transcript,
status: flag
})
}
function handleDelete(row) {
uni.showModal({
title: '提示',
content: `确定删除${row.realName}?`,
success: function(res) {
if (res.confirm) {
api.dellevelPerson(row.id).then(() => {
uni.showToast({ title: '操作成功', icon: 'none' })
getChosedStudentList()
})
}
}
})
}
import {ref} from 'vue';
import * as api from '@/common/api.js';
import {onLoad, onShow} from '@dcloudio/uni-app';
import config from '@/config.js'
import dayjs from 'dayjs'
import _ from 'underscore'
const app = getApp();
const memberInfo = app.globalData.memberInfo
const form = ref({
type: '1'
});
const examinerForChoose = ['A', 'B', 'C']
let examinerArr = []
const active = ref(0)
const infoList = ref([])
const tablePersonInfo = ref({})
const transcript = ref([]) // 补全缺失变量
const levelArr = ref([{
value: '10',
text: '十级'
}, {
value: '9',
text: '九级'
}, {
value: '8',
text: '八级'
}, {
value: '7',
text: '七级'
}, {
value: '6',
text: '六级'
}, {
value: '5',
text: '五级'
}, {
value: '4',
text: '四级'
}, {
value: '3',
text: '三级'
}, {
value: '2',
text: '二级'
}, {
value: '1',
text: '一级'
}])
const range = ref([{
value: '1',
text: '是'
}, {
value: '0',
text: '否'
}])
let examId
onLoad(option => {
if (app.globalData.isLogin) {
initData(option)
} else {
app.firstLoadCallback = () => {
initData(option)
};
}
});
function initData(option) {
form.value.memberName = app.globalData.memberInfo.name
form.value.applyTime = dayjs().format('YYYY-MM-DD')
_.each(examinerForChoose, ec => {
form.value[`examiner_${ec}`] = null
})
if (option.examId) {
examId = option.examId
// 如果是编辑模式,从URL参数获取active
if (option.step == '2') {
active.value = 1
getDetail()
getChosedStudentList()
} else {
getDetail()
}
}
}
onShow(() => {
uni.$on('chosen', updateData)
const curExamId = examId || form.value.examId
if (curExamId) {
getChosedStudentList()
}
})
function updateData(e) {
examinerArr.push(e.obj)
form.value[`examiner_${e.ec}`] = e.obj.name
}
function getDetail() {
api.getLevelApplyInfo(examId || form.value.examId).then(res => {
const data = res.data
if (data.examiner) {
_.each(data.examiner.split(','), (id, i) => {
examinerArr[i] = {perId: id}
})
_.each(data.examinerNames.split(','), (name, i) => {
data[`examiner_${examinerForChoose[i]}`] = name
if (examinerArr[i]) {
examinerArr[i].name = name
}
})
}
form.value = data
})
}
function selectFN(ec) {
const chosen = []
_.each(examinerForChoose, ecKey => {
const key = `examiner_${ecKey}`
if (form.value[key]) {
const examiner = _.find(examinerArr, (e) => {
return e.name == form.value[key]
})
if (examiner) {
chosen.push(examiner)
}
}
})
const arr = encodeURIComponent(JSON.stringify(chosen))
let path = `/level/chooseExaminer?type=${form.value.type}&chosen=${arr}&ec=${ec}`
uni.navigateTo({
url: path
});
}
function submitForm(flag) {
form.value.status = '0'
const examinerIds = []
const examinerNames = []
_.each(examinerForChoose, ec => {
const key = `examiner_${ec}`
if (form.value[key]) {
const examiner = _.find(examinerArr, (e) => {
return e.name == form.value[key]
})
if (examiner) {
examinerIds.push(examiner.perId)
examinerNames.push(examiner.name)
}
}
})
if (examinerIds.length > 0) {
form.value.examiner = examinerIds.join(',')
form.value.examinerNames = examinerNames.join(',')
} else {
form.value.examiner = null
form.value.examinerNames = null
}
// draftFlag: 0-保存 1-保存并下一步
form.value.draftFlag = flag === 0 ? '1' : '0'
if (flag === 0) {
// 仅保存
save()
} else {
// 保存并下一步 - 需校验
if (!form.value.applyTime) {
uni.showToast({title: '请选择申请日期', icon: 'none'})
return
}
if (!form.value.startTime) {
uni.showToast({title: '请选择考试开始时间', icon: 'none'})
return
}
if (!form.value.endTime) {
uni.showToast({title: '请选择考试结束时间', icon: 'none'})
return
}
if (!form.value.examLocation) {
uni.showToast({title: '请输入考级地点', icon: 'none'})
return
}
if (dayjs(form.value.startTime).valueOf() < dayjs(form.value.applyTime).valueOf()) {
uni.showToast({title: '考试开始时间应大于申请日期', icon: 'none'})
return
}
if (dayjs(form.value.endTime).valueOf() <= dayjs(form.value.startTime).valueOf()) {
uni.showToast({title: '考试结束时间应大于考试开始时间', icon: 'none'})
return
}
if (examinerIds.length % 2 === 0) {
uni.showToast({title: '录入的考官人数必须为单数', icon: 'none'})
return
}
save().then(() => {
active.value = 1
getChosedStudentList()
if (form.value.examId) {
api.getLevelApplyInfo(form.value.examId).then(res => {
if (res.data.transcript) {
transcript.value = JSON.parse(res.data.transcript)
}
})
}
})
}
}
function save() {
if (form.value.examId) {
return api.updateLevelInfo(form.value).then(() => {
uni.showToast({title: '保存成功', icon: 'none'})
})
} else {
return api.addLevelInfo(form.value).then((res) => {
form.value.examId = res.data.examId
form.value.name = res.data.name
uni.showToast({title: '保存成功', icon: 'none'})
})
}
}
function prev() {
active.value = 0
}
function goChooseStudent() {
uni.navigateTo({
url: `/level/chooseStudent?examId=${form.value.examId}&memId=${memberInfo.memId}&examType=${form.value.type}`
})
}
// 格式化日期时间
function formatDateTime(dateStr) {
if (!dateStr) return '-'
return dateStr.substring(0, 10)
}
function getChosedStudentList() {
if (!form.value.examId) return
var obj = {
examId: form.value.examId
}
api.getStudentList(obj).then(res => {
_.each(res.rows, (d) => {
if (d.levelOld) {
d.levelRecommend = (parseInt(d.levelOld) - 1) + ''
if (d.levelRecommend === '0') {
d.levelRecommend = '1'
}
} else {
d.levelRecommend = '9'
}
if (!d.levelNew) {
d.levelNew = d.levelRecommend
}
if (!d.isPass) {
d.isPass = '1'
}
if (d.photo && d.photo.indexOf('http') == -1) {
d.photo = config.baseUrl_api + d.photo
}
})
infoList.value = res.rows
}).then(getTablePersonInfo)
}
function getTablePersonInfo() {
const total = infoList.value.length
const levelArrData = []
_.each(infoList.value, (d) => {
const temp = _.find(levelArrData, (l) => {
return l.level == d.levelNew
})
if (temp) {
temp.num++
} else {
levelArrData.push({
level: d.levelNew,
num: 1
})
}
})
tablePersonInfo.value = {
total: total,
levelArr: _.sortBy(levelArrData, (l) => {
return l.level
})
}
}
function szToHz(num) {
const hzArr = ['〇', '一', '二', '三', '四', '五', '六', '七', '八', '九', '十']
return hzArr[parseInt(num)]
}
let nowRow
function changeLevelfather(row) {
nowRow = row
api.jiDropDownBox({
perId: row.perId
}).then(res => {
levelArr.value = res.data
for (let l of levelArr.value) {
l.text = l.name
l.disabled = !(l.status)
}
})
}
function changeLevel(e) {
if (e == nowRow.levelOld) {
uni.showToast({title: '考试级别重复,请重新选择!', icon: 'none'})
nowRow.levelNew = nowRow.levelRecommend
return
}
if (e !== nowRow.levelRecommend) {
uni.showModal({
title: '提示',
content: `建议考试级别为 "${szToHz(nowRow.levelRecommend)}级" ,确定要修改为${szToHz(e)}级吗?`,
success: function (res) {
if (res.confirm) {
getTablePersonInfo()
} else {
nowRow.levelNew = nowRow.levelRecommend
}
},
fail: function (res) {
nowRow.levelNew = nowRow.levelRecommend
}
})
}
}
function submitForm2(flag) {
// 循环校验考试级别
for (let item of infoList.value) {
if (item.levelNew == item.levelOld) {
uni.showToast({title: `${item.realName}考试级别重复,请重新选择!`, icon: 'none'})
return
}
if (!item.levelNew) {
uni.showToast({title: `${item.realName}请选择考试级别!`, icon: 'none'})
return
}
}
if (flag === 1) {
if (infoList.value.length == 0) {
uni.showToast({title: '请选择考生', icon: 'none'})
return
}
uni.showModal({
title: '提示',
content: `请确认人员照片是否已更新?`,
success: function (res) {
if (res.confirm) {
// saveStep2(flag).then(() => {
// uni.showToast({title: '提交成功', icon: 'none'})
// uni.navigateTo({
// url: `/level/paymentDetail?examId=${form.value.examId}`
// })
// })
uni.navigateTo({
url: `/level/paymentDetail?examId=${form.value.examId}`
})
}
}
})
} else {
saveStep2(flag).then(() => {
uni.showToast({title: '操作成功', icon: 'none'})
})
}
}
function saveStep2(flag) {
const data = _.map(infoList.value, (d) => {
return {
id: d.id,
levelNew: d.levelNew,
isPass: d.isPass
}
})
return api.editLevel({
examId: form.value.examId,
personInfo: JSON.stringify(data),
transcript: form.value.transcript,
status: flag
})
}
function handleDelete(row) {
uni.showModal({
title: '提示',
content: `确定删除${row.realName}?`,
success: function (res) {
if (res.confirm) {
api.dellevelPerson(row.id).then(() => {
uni.showToast({title: '操作成功', icon: 'none'})
getChosedStudentList()
})
}
}
})
}
</script>
<style lang="scss" scoped>
.add-apply-page {
min-height: 100vh;
background: #f5f5f5;
padding-bottom: 120rpx;
}
/* 顶部步骤条 */
.steps-bar {
display: flex;
align-items: center;
justify-content: center;
padding: 15rpx 60rpx;
background: #fff;
margin-top: 20rpx;
.step-item {
display: flex;
align-items: center;
.step-circle {
width: 48rpx;
height: 48rpx;
border-radius: 50%;
background: #fff;
border: 2rpx solid #666;
color: #666;
font-size: 26rpx;
display: flex;
align-items: center;
justify-content: center;
margin-right: 10rpx;
transition: all 0.3s;
}
.step-text {
font-size: 26rpx;
color: #666;
transition: all 0.3s;
}
&.active .step-circle {
background: #fff;
color: #AD181F;
border-color: #AD181F;
}
&.active .step-text {
color: #AD181F;
font-weight: 600;
}
&.current .step-circle {
background: #AD181F;
color: #fff;
box-shadow: 0 4rpx 12rpx rgba(173, 24, 31, 0.3);
}
&.current .step-text {
color: #AD181F;
font-weight: 600;
}
}
.step-line {
width: 120rpx;
height: 4rpx;
background: #e0e0e0;
margin: 0 20rpx;
transition: all 0.3s;
&.active {
background: #AD181F;
}
}
}
/* 步骤2样式 */
.step2-content {
padding: 0 20rpx;
margin-top: 20rpx;
}
/* 考级信息卡片 */
.exam-info-card {
background: #fff;
border-radius: 16rpx;
margin-bottom: 20rpx;
overflow: hidden;
box-shadow: 0 4rpx 20rpx rgba(0, 0, 0, 0.05);
.card-header {
padding: 24rpx 30rpx;
background: linear-gradient(135deg, #AD181F 0%, #c42a2a 100%);
.card-title {
font-size: 28rpx;
font-weight: 600;
color: #fff;
}
}
.info-grid {
display: flex;
flex-wrap: wrap;
padding: 20rpx 0;
.info-item {
width: 100%;
padding: 12rpx 30rpx;
box-sizing: border-box;
display: flex;
.info-label {
display: block;
font-size: 26rpx;
color: #666;
margin-bottom: 8rpx;
}
.info-value {
display: block;
font-size: 26rpx;
color: #333;
font-weight: 500;
margin-left: 20rpx;
}
}
}
}
/* 操作栏(统计+添加按钮) */
.action-bar {
display: flex;
justify-content: space-between;
align-items: center;
padding: 20rpx 24rpx;
background: #fff;
border-radius: 16rpx;
margin: 20rpx 0;
.stat-info {
display: flex;
align-items: center;
// justify-self: unset;
.stat-total {
font-size: 28rpx;
font-weight: 600;
color: #333;
}
.level-tags {
display: flex;
flex-wrap: wrap;
margin-left: 10rpx;
gap: 10rpx;
.level-tag {
padding: 4rpx 12rpx;
background: #FFF5F5;
border: 1rpx solid #FFDDDD;
border-radius: 6rpx;
font-size: 26rpx;
color: #AD181F;
}
}
}
}
.btn-add-student {
display: flex;
align-items: center;
justify-content: center;
padding: 0 30rpx;
height: 64rpx;
background: linear-gradient(135deg, #AD181F 0%, #c42a2a 100%);
border-radius: 32rpx;
font-size: 26rpx;
color: #fff;
box-shadow: 0 4rpx 16rpx rgba(173, 24, 31, 0.3);
}
/* 考生列表(核心优化) */
.student-list {
.student-card {
position: relative;
// display: flex;
// align-items: center;
// justify-content: space-between;
padding: 24rpx;
background: #fff;
border-radius: 16rpx;
margin-bottom: 20rpx;
box-shadow: 0 4rpx 16rpx rgba(0, 0, 0, 0.04);
/* 左侧:头像+考生信息 */
.card-left {
display: flex;
align-items: center;
flex: 1;
.avatar {
width: 80rpx;
height: 80rpx;
border-radius: 50%;
background: linear-gradient(135deg, #AD181F 0%, #c42a2a 100%);
display: flex;
align-items: center;
justify-content: center;
margin-right: 20rpx;
overflow: hidden;
.avatar-text {
font-size: 32rpx;
color: #fff;
font-weight: 600;
}
image {
width: 100%;
height: 100%;
}
}
.student-info {
.student-name {
font-size: 28rpx;
font-weight: 600;
color: #333;
margin-bottom: 8rpx;
.per-code {
font-size: 26rpx;
color: #666;
font-weight: normal;
margin-left: 12rpx;
}
}
.student-idcard {
font-size: 26rpx;
color: #666;
}
}
}
/* 右侧:原级别/考试级别/是否通过(垂直布局,完美对齐) */
.card-right {
display: flex;
justify-content: space-between;
// padding:0 30px;
margin-top: 20rpx;
margin-left:100rpx;
// flex-direction: column;
// align-items: flex-end;
// gap: 16rpx;
.level-item {
display: flex;
flex-direction: column;
align-items: flex-end;
.level-label {
font-size: 26rpx;
color: #666;
margin-bottom: 6rpx;
}
.level-value {
font-size: 28rpx;
color: #333;
font-weight: 500;
}
.select-wrapper {
width: 120rpx;
}
}
}
/* 删除按钮 */
.delete-btn {
position: absolute;
top: 16rpx;
right: 16rpx;
padding: 8rpx;
}
}
/* 空状态 */
.empty-state {
display: flex;
flex-direction: column;
align-items: center;
justify-content: center;
padding: 80rpx 0;
background: #fff;
border-radius: 16rpx;
image {
width: 240rpx;
height: 240rpx;
margin-bottom: 20rpx;
}
text {
font-size: 26rpx;
color: #666;
}
}
}
.wBox {
width: 700rpx;
padding: 30rpx;
margin: 20rpx auto;
background: #FFFFFF;
box-shadow: 0rpx 12rpx 116rpx 0rpx rgba(196, 203, 214, 0.1);
border-radius: 15rpx;
}
:deep(.uni-forms-item__inner) {
padding-bottom: 20rpx;
}
.maskbox {
position: relative;
.mask {
position: absolute;
width: calc(100% - 34px);
height: 100%;
z-index: 10;
background-color: red;
opacity: 0;
}
}
/* 底部按钮 */
.fixedBottom {
position: fixed;
bottom: 0;
left: 0;
right: 0;
display: flex;
justify-content: space-around;
align-items: center;
padding: 20rpx 0;
background: #fff;
border-top: 1rpx solid #f0f0f0;
z-index: 98;
.btn-red {
background: linear-gradient(135deg, #AD181F 0%, #c42a2a 100%);
color: #fff;
border: none;
border-radius: 32rpx;
height: 72rpx;
font-size: 28rpx;
font-weight: 600;
}
.btn-red-kx {
background: #fff;
color: #AD181F;
border: 2rpx solid #AD181F;
border-radius: 32rpx;
height: 72rpx;
font-size: 28rpx;
font-weight: 600;
}
}
</style>
\ No newline at end of file
.add-apply-page {
min-height: 100vh;
background: #f5f5f5;
padding-bottom: 120rpx;
}
/* 顶部步骤条 */
.steps-bar {
display: flex;
align-items: center;
justify-content: center;
padding: 15rpx 60rpx;
background: #fff;
margin-top: 20rpx;
.step-item {
display: flex;
align-items: center;
.step-circle {
width: 48rpx;
height: 48rpx;
border-radius: 50%;
background: #fff;
border: 2rpx solid #666;
color: #666;
font-size: 26rpx;
display: flex;
align-items: center;
justify-content: center;
margin-right: 10rpx;
transition: all 0.3s;
}
.step-text {
font-size: 26rpx;
color: #666;
transition: all 0.3s;
}
&.active .step-circle {
background: #fff;
color: #AD181F;
border-color: #AD181F;
}
&.active .step-text {
color: #AD181F;
font-weight: 600;
}
&.current .step-circle {
background: #AD181F;
color: #fff;
box-shadow: 0 4rpx 12rpx rgba(173, 24, 31, 0.3);
}
&.current .step-text {
color: #AD181F;
font-weight: 600;
}
}
.step-line {
width: 120rpx;
height: 4rpx;
background: #e0e0e0;
margin: 0 20rpx;
transition: all 0.3s;
&.active {
background: #AD181F;
}
}
}
/* 步骤2样式 */
.step2-content {
padding: 0 20rpx;
margin-top: 20rpx;
}
/* 考级信息卡片 */
.exam-info-card {
background: #fff;
border-radius: 16rpx;
margin-bottom: 20rpx;
overflow: hidden;
box-shadow: 0 4rpx 20rpx rgba(0, 0, 0, 0.05);
.card-header {
padding: 24rpx 30rpx;
background: linear-gradient(135deg, #AD181F 0%, #c42a2a 100%);
.card-title {
font-size: 28rpx;
font-weight: 600;
color: #fff;
}
}
.info-grid {
display: flex;
flex-wrap: wrap;
padding: 20rpx 0;
.info-item {
width: 100%;
padding: 12rpx 30rpx;
box-sizing: border-box;
display: flex;
.info-label {
display: block;
font-size: 26rpx;
color: #666;
margin-bottom: 8rpx;
}
.info-value {
display: block;
font-size: 26rpx;
color: #333;
font-weight: 500;
margin-left: 20rpx;
}
}
}
}
/* 操作栏(统计+添加按钮) */
.action-bar {
display: flex;
justify-content: space-between;
align-items: center;
padding: 20rpx 24rpx;
background: #fff;
border-radius: 16rpx;
margin: 20rpx 0;
.stat-info {
display: flex;
align-items: center;
// justify-self: unset;
.stat-total {
font-size: 28rpx;
font-weight: 600;
color: #333;
}
.level-tags {
display: flex;
flex-wrap: wrap;
margin-left: 10rpx;
gap: 10rpx;
.level-tag {
padding: 4rpx 12rpx;
background: #FFF5F5;
border: 1rpx solid #FFDDDD;
border-radius: 6rpx;
font-size: 26rpx;
color: #AD181F;
}
}
}
}
.btn-add-student {
display: flex;
align-items: center;
justify-content: center;
padding: 0 30rpx;
height: 64rpx;
background: linear-gradient(135deg, #AD181F 0%, #c42a2a 100%);
border-radius: 32rpx;
font-size: 26rpx;
color: #fff;
box-shadow: 0 4rpx 16rpx rgba(173, 24, 31, 0.3);
}
/* 考生列表(核心优化) */
.student-list {
.student-card {
position: relative;
// display: flex;
// align-items: center;
// justify-content: space-between;
padding: 24rpx;
background: #fff;
border-radius: 16rpx;
margin-bottom: 20rpx;
box-shadow: 0 4rpx 16rpx rgba(0, 0, 0, 0.04);
/* 左侧:头像+考生信息 */
.card-left {
display: flex;
align-items: center;
flex: 1;
.avatar {
width: 80rpx;
height: 80rpx;
border-radius: 50%;
background: linear-gradient(135deg, #AD181F 0%, #c42a2a 100%);
display: flex;
align-items: center;
justify-content: center;
margin-right: 20rpx;
overflow: hidden;
.avatar-text {
font-size: 32rpx;
color: #fff;
font-weight: 600;
}
image {
width: 100%;
height: 100%;
}
}
.student-info {
.student-name {
font-size: 28rpx;
font-weight: 600;
color: #333;
margin-bottom: 8rpx;
.per-code {
font-size: 26rpx;
color: #666;
font-weight: normal;
margin-left: 12rpx;
}
}
.student-idcard {
font-size: 26rpx;
color: #666;
}
}
}
/* 右侧:原级别/考试级别/是否通过(垂直布局,完美对齐) */
.card-right {
display: flex;
justify-content: space-between;
// padding:0 30px;
margin-top: 20rpx;
margin-left: 100rpx;
// flex-direction: column;
// align-items: flex-end;
// gap: 16rpx;
.level-item {
display: flex;
flex-direction: column;
align-items: flex-end;
.level-label {
font-size: 26rpx;
color: #666;
margin-bottom: 6rpx;
}
.level-value {
font-size: 28rpx;
color: #333;
font-weight: 500;
}
.select-wrapper {
width: 120rpx;
}
}
}
/* 删除按钮 */
.delete-btn {
position: absolute;
top: 16rpx;
right: 16rpx;
padding: 8rpx;
}
}
/* 空状态 */
.empty-state {
display: flex;
flex-direction: column;
align-items: center;
justify-content: center;
padding: 80rpx 0;
background: #fff;
border-radius: 16rpx;
image {
width: 240rpx;
height: 240rpx;
margin-bottom: 20rpx;
}
text {
font-size: 26rpx;
color: #666;
}
}
}
.wBox {
width: 700rpx;
padding: 30rpx;
margin: 20rpx auto;
background: #FFFFFF;
box-shadow: 0rpx 12rpx 116rpx 0rpx rgba(196, 203, 214, 0.1);
border-radius: 15rpx;
}
:deep(.uni-forms-item__inner) {
padding-bottom: 20rpx;
}
.maskbox {
position: relative;
.mask {
position: absolute;
width: calc(100% - 34px);
height: 100%;
z-index: 10;
background-color: red;
opacity: 0;
}
}
/* 底部按钮 */
.fixedBottom {
position: fixed;
bottom: 0;
left: 0;
right: 0;
display: flex;
justify-content: space-around;
align-items: center;
padding: 20rpx 0;
background: #fff;
border-top: 1rpx solid #f0f0f0;
z-index: 98;
.btn-red {
background: linear-gradient(135deg, #AD181F 0%, #c42a2a 100%);
color: #fff;
border: none;
border-radius: 32rpx;
height: 72rpx;
font-size: 28rpx;
font-weight: 600;
}
.btn-red-kx {
background: #fff;
color: #AD181F;
border: 2rpx solid #AD181F;
border-radius: 32rpx;
height: 72rpx;
font-size: 28rpx;
font-weight: 600;
}
}
</style>
......
......@@ -213,13 +213,16 @@ const handleSubmit = async () => {
content: `确定提交订单吗?`,
success: async (res) => {
if (res.confirm) {
uni.showLoading({title: '提交中...'});
uni.showLoading({
title: '支付中...',
mask: true
})
try {
const commitRes = await api.commitJiExam({
addresId: selectedAddress.value.id,
id: examId.value,
payType: '2'
});
})
if (commitRes.data && commitRes.data.payResult.encryptedData) {
const res = await minShengPay(commitRes.data.orderId, commitRes.data.payResult.encryptedData)
if (res == 'OK') {
......@@ -233,44 +236,6 @@ const handleSubmit = async () => {
}
}
// if (commitRes.data && commitRes.data.orderId) {
// // 有支付流程,调用支付
// const payRes = await api.payJiExam(commitRes.data.orderId);
// uni.hideLoading();
//
// if (payRes.data && payRes.data.payResult && payRes.data.payResult.encryptedData) {
// // 调用支付
// uni.requestPayment({
// provider: 'wxpay',
// timeStamp: payRes.data.payResult.timeStamp,
// nonceStr: payRes.data.payResult.nonceStr,
// package: payRes.data.payResult.package,
// signType: payRes.data.payResult.signType,
// paySign: payRes.data.payResult.paySign,
// success: () => {
// uni.showToast({title: '支付成功', icon: 'success'});
// setTimeout(() => {
// uni.navigateBack();
// }, 1500);
// },
// fail: () => {
// uni.showToast({title: '支付失败', icon: 'none'});
// }
// });
// } else {
// // 无需支付,直接成功
// uni.showToast({title: '提交成功', icon: 'success'});
// setTimeout(() => {
// uni.navigateBack();
// }, 1500);
// }
// } else {
// uni.hideLoading();
// uni.showToast({title: '提交成功', icon: 'success'});
// setTimeout(() => {
// uni.navigateBack();
// }, 1500);
// }
} catch (e) {
uni.hideLoading();
console.error('提交失败', e);
......
......@@ -108,7 +108,7 @@ async function handlePay() {
try {
payLoading.value = true
uni.showToast({
uni.showLoading({
title: '支付中...',
mask: true
})
......@@ -134,6 +134,7 @@ async function handlePay() {
// 跳转到支付成功页
} catch (err) {
console.log(err)
const errMsg = err?.data?.msg || err?.message || '支付失败,请稍后重试'
uni.showToast({
title: errMsg,
......
Styling with Markdown is supported
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!