476 lines
13 KiB
Vue
476 lines
13 KiB
Vue
|
|
<template>
|
|||
|
|
<BasicLayout>
|
|||
|
|
<view class="p-15">
|
|||
|
|
<!-- 积分标准 -->
|
|||
|
|
<view class="jf-info-section">
|
|||
|
|
<view class="section-title">积分标准</view>
|
|||
|
|
<view class="info-item">
|
|||
|
|
<text class="label">积分项目:</text>
|
|||
|
|
<text class="value title-bold">{{ jfInfo.jfTypeName || '-' }}</text>
|
|||
|
|
</view>
|
|||
|
|
<view class="info-block">
|
|||
|
|
<text class="block-label">检查标准</text>
|
|||
|
|
<text class="block-value multi-text">{{ jfInfo.ruleStandard || '-' }}</text>
|
|||
|
|
</view>
|
|||
|
|
<view class="info-block">
|
|||
|
|
<text class="block-label">业绩积分</text>
|
|||
|
|
<view v-if="formattedScoreConfig.length" class="score-config-wrapper">
|
|||
|
|
<view
|
|||
|
|
v-for="(category, catIdx) in formattedScoreConfig"
|
|||
|
|
:key="catIdx"
|
|||
|
|
class="score-config-category"
|
|||
|
|
>
|
|||
|
|
<view v-if="category.category" class="category-title">{{ category.category }}</view>
|
|||
|
|
<view v-if="!category.hasMultipleGrades" class="score-config-table">
|
|||
|
|
<view class="table-header">
|
|||
|
|
<view class="table-cell header-cell">级别</view>
|
|||
|
|
<view class="table-cell header-cell">分值</view>
|
|||
|
|
</view>
|
|||
|
|
<view v-for="(row, idx) in category.rows" :key="idx" class="table-row">
|
|||
|
|
<view class="table-cell">{{ row.level }}</view>
|
|||
|
|
<view class="table-cell score-cell">{{ row.scores }}</view>
|
|||
|
|
</view>
|
|||
|
|
</view>
|
|||
|
|
<view v-else class="score-config-table">
|
|||
|
|
<view class="table-header">
|
|||
|
|
<view class="table-cell header-cell">级别</view>
|
|||
|
|
<view class="table-cell header-cell">一等奖</view>
|
|||
|
|
<view class="table-cell header-cell">二等奖</view>
|
|||
|
|
<view class="table-cell header-cell">三等奖</view>
|
|||
|
|
</view>
|
|||
|
|
<view v-for="(row, idx) in category.rows" :key="idx" class="table-row">
|
|||
|
|
<view class="table-cell">{{ row.level }}</view>
|
|||
|
|
<view class="table-cell score-cell">{{ Array.isArray(row.scores) ? (row.scores[0] || '') : '' }}</view>
|
|||
|
|
<view class="table-cell score-cell">{{ Array.isArray(row.scores) ? (row.scores[1] || '') : '' }}</view>
|
|||
|
|
<view class="table-cell score-cell">{{ Array.isArray(row.scores) ? (row.scores[2] || '') : '' }}</view>
|
|||
|
|
</view>
|
|||
|
|
</view>
|
|||
|
|
</view>
|
|||
|
|
</view>
|
|||
|
|
<view v-else class="block-value placeholder">暂无配置</view>
|
|||
|
|
</view>
|
|||
|
|
</view>
|
|||
|
|
|
|||
|
|
<!-- 获奖情况 -->
|
|||
|
|
<view class="jf-info-section">
|
|||
|
|
<view class="section-title">获奖情况</view>
|
|||
|
|
<view class="info-item">
|
|||
|
|
<text class="label">考核教师:</text>
|
|||
|
|
<text class="value title-bold">{{ jfInfo.jsmx || '-' }}</text>
|
|||
|
|
</view>
|
|||
|
|
<view class="info-item">
|
|||
|
|
<text class="label">荣誉名称:</text>
|
|||
|
|
<text class="value">{{ jfInfo.rymc || '-' }}</text>
|
|||
|
|
</view>
|
|||
|
|
<view class="info-item">
|
|||
|
|
<text class="label">获奖类型:</text>
|
|||
|
|
<text class="value">{{ jfInfo.hjlx || '-' }}</text>
|
|||
|
|
</view>
|
|||
|
|
<view class="info-item">
|
|||
|
|
<text class="label">颁奖单位:</text>
|
|||
|
|
<text class="value multi-text">{{ jfInfo.bjdw || '-' }}</text>
|
|||
|
|
</view>
|
|||
|
|
<view class="info-item">
|
|||
|
|
<text class="label">获奖时间:</text>
|
|||
|
|
<text class="value">{{ formatYearMonth(jfInfo.hjtime) }}</text>
|
|||
|
|
</view>
|
|||
|
|
<view class="info-item">
|
|||
|
|
<text class="label">类别:</text>
|
|||
|
|
<text class="value">{{ jfInfo.category || '-' }}</text>
|
|||
|
|
</view>
|
|||
|
|
<view class="info-item">
|
|||
|
|
<text class="label">级别:</text>
|
|||
|
|
<text class="value">{{ jfInfo.level || '-' }}</text>
|
|||
|
|
</view>
|
|||
|
|
<view class="info-item" v-if="jfInfo.grade">
|
|||
|
|
<text class="label">等级:</text>
|
|||
|
|
<text class="value">{{ jfInfo.grade }}</text>
|
|||
|
|
</view>
|
|||
|
|
<view class="info-item">
|
|||
|
|
<text class="label">分值:</text>
|
|||
|
|
<text class="value score-value">{{ jfInfo.score ?? '-' }}</text>
|
|||
|
|
</view>
|
|||
|
|
</view>
|
|||
|
|
|
|||
|
|
<!-- 证书预览 -->
|
|||
|
|
<BasicFilePreview
|
|||
|
|
v-if="jfInfo.fileUrl"
|
|||
|
|
:file-url="jfInfo.fileUrl"
|
|||
|
|
:file-name="jfInfo.fileName"
|
|||
|
|
:file-format="jfInfo.fileFormat"
|
|||
|
|
class="mb-0"
|
|||
|
|
/>
|
|||
|
|
</view>
|
|||
|
|
|
|||
|
|
<!-- 审批流程展示 -->
|
|||
|
|
<LcglSp :yw-id="jfId" yw-type="JF" />
|
|||
|
|
|
|||
|
|
<template #bottom>
|
|||
|
|
<YwConfirm
|
|||
|
|
v-if="showButton"
|
|||
|
|
:spApi="jfSpApi"
|
|||
|
|
:stopApi="jfStopApi"
|
|||
|
|
:transferApi="jfTransferApi"
|
|||
|
|
:params="spParams"
|
|||
|
|
:showXt="false"
|
|||
|
|
:showReject="true"
|
|||
|
|
:showTransfer="true"
|
|||
|
|
:showApprove="true"
|
|||
|
|
:showReturn="false"
|
|||
|
|
:showStop="true"
|
|||
|
|
:showXtDk="false"
|
|||
|
|
/>
|
|||
|
|
</template>
|
|||
|
|
</BasicLayout>
|
|||
|
|
</template>
|
|||
|
|
|
|||
|
|
<script setup lang="ts">
|
|||
|
|
import { onLoad } from "@dcloudio/uni-app";
|
|||
|
|
import { ref, computed } from "vue";
|
|||
|
|
import dayjs from "dayjs";
|
|||
|
|
import BasicLayout from "@/components/BasicLayout/Layout.vue";
|
|||
|
|
import LcglSp from "@/components/LcglSp/index.vue";
|
|||
|
|
import YwConfirm from "@/pages/components/YwConfirm/index.vue";
|
|||
|
|
import BasicFilePreview from "@/components/BasicFile/preview.vue";
|
|||
|
|
import { jfFlowByIdApi, jfSpApi, jfTransferApi, jfStopApi } from "@/api/base/server";
|
|||
|
|
import { useDataStore } from "@/store/modules/data";
|
|||
|
|
|
|||
|
|
const { getXxts } = useDataStore();
|
|||
|
|
|
|||
|
|
const jfId = ref<string>("");
|
|||
|
|
const jfInfo = ref<any>({});
|
|||
|
|
const showButton = ref<boolean>(false);
|
|||
|
|
|
|||
|
|
const spParams = computed(() => ({
|
|||
|
|
xxtsId: getXxts?.id,
|
|||
|
|
ywId: jfId.value
|
|||
|
|
}));
|
|||
|
|
|
|||
|
|
// 时间格式化
|
|||
|
|
const formatTime = (time: any) => {
|
|||
|
|
if (!time) return "-";
|
|||
|
|
return dayjs(time).format("YYYY-MM-DD HH:mm:ss");
|
|||
|
|
};
|
|||
|
|
|
|||
|
|
const formatYearMonth = (time: any) => {
|
|||
|
|
if (!time) return "-";
|
|||
|
|
return dayjs(time).format("YYYY-MM");
|
|||
|
|
};
|
|||
|
|
|
|||
|
|
// ===== 业绩积分展示格式化(与 MyScoreDetail 同步) =====
|
|||
|
|
const defaultLevels = [
|
|||
|
|
{ levelCode: 'national', levelName: '国', key: 'levelNational' },
|
|||
|
|
{ levelCode: 'province', levelName: '省', key: 'levelProvince' },
|
|||
|
|
{ levelCode: 'city', levelName: '市', key: 'levelCity' },
|
|||
|
|
{ levelCode: 'district', levelName: '区', key: 'levelDistrict' },
|
|||
|
|
{ levelCode: 'school_district', levelName: '学区/街道', key: 'levelSchoolDistrict' },
|
|||
|
|
{ levelCode: 'school', levelName: '校', key: 'levelSchool' },
|
|||
|
|
];
|
|||
|
|
|
|||
|
|
interface ScoreConfigRow {
|
|||
|
|
level: string;
|
|||
|
|
scores: string | number[]; // 单个分值用字符串,多个分值用数组
|
|||
|
|
hasMultipleGrades: boolean; // 是否有多个等级
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
interface ScoreConfigCategory {
|
|||
|
|
category?: string;
|
|||
|
|
rows: ScoreConfigRow[];
|
|||
|
|
hasMultipleGrades: boolean; // 整个类别是否有多个等级
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
const formatScores = (scores: number[]): { display: string | number[], hasMultiple: boolean } => {
|
|||
|
|
if (!scores || scores.length === 0) {
|
|||
|
|
return { display: '', hasMultiple: false };
|
|||
|
|
}
|
|||
|
|
const validScores = scores.filter(s => s > 0);
|
|||
|
|
if (validScores.length === 0) {
|
|||
|
|
return { display: '', hasMultiple: false };
|
|||
|
|
}
|
|||
|
|
if (validScores.length === 1) {
|
|||
|
|
return { display: String(validScores[0]), hasMultiple: false };
|
|||
|
|
}
|
|||
|
|
return { display: validScores, hasMultiple: true };
|
|||
|
|
};
|
|||
|
|
|
|||
|
|
const formatScoreConfig = (config: any): ScoreConfigCategory[] => {
|
|||
|
|
if (!config) return [];
|
|||
|
|
try {
|
|||
|
|
let configObj = config;
|
|||
|
|
if (typeof config === "string") {
|
|||
|
|
try {
|
|||
|
|
configObj = JSON.parse(config);
|
|||
|
|
} catch {
|
|||
|
|
return [];
|
|||
|
|
}
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
const result: ScoreConfigCategory[] = [];
|
|||
|
|
|
|||
|
|
if (configObj.categories && Array.isArray(configObj.categories)) {
|
|||
|
|
configObj.categories.forEach((cat: any) => {
|
|||
|
|
const categoryName = cat.category || '';
|
|||
|
|
const rows: ScoreConfigRow[] = [];
|
|||
|
|
let categoryHasMultiple = false;
|
|||
|
|
|
|||
|
|
defaultLevels.forEach(level => {
|
|||
|
|
const scores = cat[level.key] as number[];
|
|||
|
|
if (scores && scores.length > 0) {
|
|||
|
|
const formatted = formatScores(scores);
|
|||
|
|
if (formatted.display) {
|
|||
|
|
if (formatted.hasMultiple) {
|
|||
|
|
categoryHasMultiple = true;
|
|||
|
|
}
|
|||
|
|
rows.push({
|
|||
|
|
level: level.levelName,
|
|||
|
|
scores: formatted.display,
|
|||
|
|
hasMultipleGrades: formatted.hasMultiple
|
|||
|
|
});
|
|||
|
|
}
|
|||
|
|
}
|
|||
|
|
});
|
|||
|
|
|
|||
|
|
if (rows.length > 0) {
|
|||
|
|
result.push({
|
|||
|
|
category: categoryName,
|
|||
|
|
rows: rows,
|
|||
|
|
hasMultipleGrades: categoryHasMultiple
|
|||
|
|
});
|
|||
|
|
}
|
|||
|
|
});
|
|||
|
|
} else if (configObj.category && configObj.levels) {
|
|||
|
|
const rows: ScoreConfigRow[] = [];
|
|||
|
|
let categoryHasMultiple = false;
|
|||
|
|
|
|||
|
|
configObj.levels.forEach((level: any) => {
|
|||
|
|
if (level.scores && level.scores.length > 0) {
|
|||
|
|
const formatted = formatScores(level.scores);
|
|||
|
|
if (formatted.display) {
|
|||
|
|
if (formatted.hasMultiple) {
|
|||
|
|
categoryHasMultiple = true;
|
|||
|
|
}
|
|||
|
|
const levelName = level.levelName || level.levelCode || '';
|
|||
|
|
rows.push({
|
|||
|
|
level: levelName,
|
|||
|
|
scores: formatted.display,
|
|||
|
|
hasMultipleGrades: formatted.hasMultiple
|
|||
|
|
});
|
|||
|
|
}
|
|||
|
|
}
|
|||
|
|
});
|
|||
|
|
|
|||
|
|
if (rows.length > 0) {
|
|||
|
|
result.push({
|
|||
|
|
category: configObj.category,
|
|||
|
|
rows: rows,
|
|||
|
|
hasMultipleGrades: categoryHasMultiple
|
|||
|
|
});
|
|||
|
|
}
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
return result;
|
|||
|
|
} catch {
|
|||
|
|
return [];
|
|||
|
|
}
|
|||
|
|
};
|
|||
|
|
|
|||
|
|
const formattedScoreConfig = computed(() => formatScoreConfig(jfInfo.value?.scoreConfig));
|
|||
|
|
|
|||
|
|
// 读取流程详情
|
|||
|
|
const getJfInfo = async () => {
|
|||
|
|
try {
|
|||
|
|
const res: any = await jfFlowByIdApi({ id: jfId.value });
|
|||
|
|
if (res && res.resultCode === 1 && res.result) {
|
|||
|
|
jfInfo.value = res.result.jfInfo || {};
|
|||
|
|
const spResult = jfInfo.value?.spResult;
|
|||
|
|
// 当流程已完成且待办状态关闭时,不显示审批按钮
|
|||
|
|
if (spResult && spResult !== "A" && getXxts && getXxts.dbZt === "A") {
|
|||
|
|
showButton.value = false;
|
|||
|
|
} else {
|
|||
|
|
showButton.value = true;
|
|||
|
|
}
|
|||
|
|
} else {
|
|||
|
|
showButton.value = false;
|
|||
|
|
}
|
|||
|
|
} catch (error) {
|
|||
|
|
console.error("获取积分流程失败:", error);
|
|||
|
|
showButton.value = false;
|
|||
|
|
}
|
|||
|
|
};
|
|||
|
|
|
|||
|
|
onLoad((options: any) => {
|
|||
|
|
if (options && options.id) {
|
|||
|
|
jfId.value = options.id;
|
|||
|
|
getJfInfo();
|
|||
|
|
} else {
|
|||
|
|
uni.showToast({ title: "缺少积分ID", icon: "none" });
|
|||
|
|
setTimeout(() => uni.navigateBack(), 1500);
|
|||
|
|
}
|
|||
|
|
});
|
|||
|
|
</script>
|
|||
|
|
|
|||
|
|
<style scoped lang="scss">
|
|||
|
|
.p-15 {
|
|||
|
|
padding: 15px;
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
.jf-info-section {
|
|||
|
|
margin-bottom: 20px;
|
|||
|
|
padding: 15px;
|
|||
|
|
background: #fff;
|
|||
|
|
border-radius: 8px;
|
|||
|
|
box-shadow: 0 2px 8px rgba(0, 0, 0, 0.1);
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
.section-title {
|
|||
|
|
font-size: 16px;
|
|||
|
|
font-weight: bold;
|
|||
|
|
margin-bottom: 15px;
|
|||
|
|
color: #333;
|
|||
|
|
border-bottom: 2px solid #007aff;
|
|||
|
|
padding-bottom: 5px;
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
.info-item {
|
|||
|
|
display: flex;
|
|||
|
|
margin-bottom: 12px;
|
|||
|
|
|
|||
|
|
.label {
|
|||
|
|
width: 110rpx;
|
|||
|
|
color: #666;
|
|||
|
|
font-size: 28rpx;
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
.value {
|
|||
|
|
flex: 1;
|
|||
|
|
color: #333;
|
|||
|
|
font-size: 28rpx;
|
|||
|
|
|
|||
|
|
&.title-bold {
|
|||
|
|
font-weight: bold;
|
|||
|
|
font-size: 32rpx;
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
&.score-value {
|
|||
|
|
color: #f56c6c;
|
|||
|
|
font-weight: 600;
|
|||
|
|
}
|
|||
|
|
}
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
.info-block {
|
|||
|
|
margin-top: 12px;
|
|||
|
|
|
|||
|
|
.block-label {
|
|||
|
|
display: inline-block;
|
|||
|
|
font-size: 28rpx;
|
|||
|
|
font-weight: 600;
|
|||
|
|
color: #303133;
|
|||
|
|
padding-bottom: 6rpx;
|
|||
|
|
border-bottom: 2rpx solid #e4e7ed;
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
.block-value {
|
|||
|
|
display: block;
|
|||
|
|
margin-top: 8rpx;
|
|||
|
|
font-size: 28rpx;
|
|||
|
|
color: #606266;
|
|||
|
|
|
|||
|
|
&.multi-text {
|
|||
|
|
white-space: pre-wrap;
|
|||
|
|
word-break: break-word;
|
|||
|
|
line-height: 1.6;
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
&.placeholder {
|
|||
|
|
color: #999;
|
|||
|
|
}
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
.score-config-wrapper {
|
|||
|
|
width: 100%;
|
|||
|
|
margin-top: 8rpx;
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
.score-config-category {
|
|||
|
|
margin-top: 16rpx;
|
|||
|
|
|
|||
|
|
&:first-child {
|
|||
|
|
margin-top: 8rpx;
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
.category-title {
|
|||
|
|
font-size: 28rpx;
|
|||
|
|
font-weight: 600;
|
|||
|
|
color: #409eff;
|
|||
|
|
margin-bottom: 12rpx;
|
|||
|
|
padding: 8rpx 12rpx;
|
|||
|
|
background-color: #ecf5ff;
|
|||
|
|
border-radius: 6rpx;
|
|||
|
|
border-left: 4rpx solid #409eff;
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
.score-config-table {
|
|||
|
|
border: 1rpx solid #dcdfe6;
|
|||
|
|
border-radius: 8rpx;
|
|||
|
|
overflow: hidden;
|
|||
|
|
|
|||
|
|
.table-header {
|
|||
|
|
display: flex;
|
|||
|
|
background-color: #f5f7fa;
|
|||
|
|
border-bottom: 1rpx solid #dcdfe6;
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
.table-row {
|
|||
|
|
display: flex;
|
|||
|
|
border-bottom: 1rpx solid #ebeef5;
|
|||
|
|
|
|||
|
|
&:last-child {
|
|||
|
|
border-bottom: none;
|
|||
|
|
}
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
.table-cell {
|
|||
|
|
padding: 16rpx 12rpx;
|
|||
|
|
font-size: 26rpx;
|
|||
|
|
text-align: center;
|
|||
|
|
border-right: 1rpx solid #ebeef5;
|
|||
|
|
|
|||
|
|
&:first-child {
|
|||
|
|
width: 120rpx;
|
|||
|
|
border-right: 1rpx solid #ebeef5;
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
&:nth-child(2):last-child {
|
|||
|
|
flex: 1;
|
|||
|
|
border-right: none;
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
&:nth-child(2):not(:last-child),
|
|||
|
|
&:nth-child(3),
|
|||
|
|
&:nth-child(4) {
|
|||
|
|
flex: 1;
|
|||
|
|
min-width: 100rpx;
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
&:last-child {
|
|||
|
|
border-right: none;
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
&.header-cell {
|
|||
|
|
font-weight: bold;
|
|||
|
|
color: #303133;
|
|||
|
|
background-color: #f5f7fa;
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
&.score-cell {
|
|||
|
|
color: #409eff;
|
|||
|
|
font-weight: 500;
|
|||
|
|
}
|
|||
|
|
}
|
|||
|
|
}
|
|||
|
|
}
|
|||
|
|
}
|
|||
|
|
</style>
|
|||
|
|
|