新苗调整
This commit is contained in:
parent
dda9a21de3
commit
8bdde206b0
@ -68,6 +68,12 @@ export const xsKsccApi = async (params: any) => {
|
||||
return await get("/mobile/jz/kscc", params);
|
||||
};
|
||||
|
||||
/**
|
||||
* 学期-考试场次树;可选 bjId:后端按 yfzc_kscc.bj_id 过滤(家长端传当前学生班级)
|
||||
*/
|
||||
export const ksccFindAllXqKsccTreeApi = (params?: { bjId?: string }) =>
|
||||
get("/api/kscc/findAllXqKsccTree", params ?? {});
|
||||
|
||||
/**
|
||||
* 查询学生考试成绩
|
||||
*/
|
||||
|
||||
@ -175,6 +175,13 @@
|
||||
"enablePullDownRefresh": false
|
||||
}
|
||||
},
|
||||
{
|
||||
"path": "pages/base/xszp/resource-detail",
|
||||
"style": {
|
||||
"navigationBarTitleText": "资源详情",
|
||||
"enablePullDownRefresh": false
|
||||
}
|
||||
},
|
||||
{
|
||||
"path": "pages/base/jl/detailwb",
|
||||
"style": {
|
||||
@ -220,8 +227,8 @@
|
||||
{
|
||||
"path": "pages/base/grades/list",
|
||||
"style": {
|
||||
"navigationBarTitleText": "考试列表",
|
||||
"enablePullDownRefresh": false
|
||||
"navigationBarTitleText": "成绩查询",
|
||||
"enablePullDownRefresh": true
|
||||
}
|
||||
},
|
||||
{
|
||||
|
||||
@ -20,7 +20,7 @@
|
||||
<view class="score-info-section">
|
||||
<view class="score-left">
|
||||
<text class="total-score">共{{ ksccKmList.length }}科</text>
|
||||
<text class="full-score">满分{{ totalKmFs }}分</text>
|
||||
<text v-if="showXsFs" class="full-score">满分{{ totalKmFs }}分</text>
|
||||
</view>
|
||||
<text class="grade">{{ curKsdj.dj || '-' }}</text>
|
||||
</view>
|
||||
@ -59,12 +59,19 @@
|
||||
>
|
||||
<view class="subject-header">
|
||||
<text class="subject-name">{{ kscj.km?.kmmc || kscj.kmmc || '未知科目' }}</text>
|
||||
<text class="detail-btn" :style="{ color: kscj.djclr || '#909399' }" v-if="kscj.dj">{{ kscj.djBx }}</text>
|
||||
<!-- sf_xs_fs=0:隐藏右侧等级表现文案(如优秀);左侧字母等级 dj 仍展示 -->
|
||||
<text
|
||||
class="detail-btn"
|
||||
:style="{ color: kscj.djclr || '#909399' }"
|
||||
v-if="showXsFs && kscj.djBx"
|
||||
>
|
||||
{{ kscj.djBx }}
|
||||
</text>
|
||||
</view>
|
||||
<view class="subject-body">
|
||||
<text class="subject-grade" :style="{ color: kscj.djclr || '#303133' }">{{ kscj.dj || '-' }}</text>
|
||||
<view class="grade-info-wrapper">
|
||||
<text v-if="kscc.sfXsFs && kscj.ksfs" class="subject-score">{{ kscj.ksfs }}</text>
|
||||
<view class="grade-info-wrapper" v-if="showXsFs">
|
||||
<text v-if="showSubjectNumericScore(kscj)" class="subject-score">{{ kscj.ksfs }}</text>
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
@ -103,6 +110,7 @@
|
||||
|
||||
<script setup lang="ts">
|
||||
import { ref, onMounted, watch, nextTick } from "vue";
|
||||
import { onLoad } from "@dcloudio/uni-app";
|
||||
import uCharts from "@/components/charts/u-charts.js";
|
||||
import dayjs from "dayjs";
|
||||
import { xsKscjApi, ksccPjFindByKsccAndXsApi } from "@/api/base/server";
|
||||
@ -119,6 +127,42 @@ const fsScale = 100;
|
||||
const curXs = ref<any>({})
|
||||
const kscc = ref<any>({})
|
||||
|
||||
/** 从列表 URL 带入场次,避免依赖全局 store */
|
||||
const ksccFromRoute = ref(false)
|
||||
|
||||
/** 与 yfzc_kscc.sf_xs_fs 一致:接口 showFs=false 时不展示卷面分及科目右侧等级表现文案(djBx);各科字母等级 dj 与顶部总等级仍展示 */
|
||||
const showXsFs = ref(true);
|
||||
|
||||
function showSubjectNumericScore(kscj: any): boolean {
|
||||
if (!showXsFs.value) return false;
|
||||
if (kscj == null || kscj.ksfs === undefined || kscj.ksfs === null || kscj.ksfs === "") return false;
|
||||
return true;
|
||||
}
|
||||
|
||||
onLoad((options?: Record<string, string>) => {
|
||||
const q = options || {};
|
||||
const kid = q.ksccId != null ? String(q.ksccId).trim() : "";
|
||||
if (!kid) return;
|
||||
ksccFromRoute.value = true;
|
||||
let name = "";
|
||||
try {
|
||||
name = q.ksmc != null ? decodeURIComponent(String(q.ksmc)) : "";
|
||||
} catch {
|
||||
name = q.ksmc != null ? String(q.ksmc) : "";
|
||||
}
|
||||
kscc.value = {
|
||||
id: kid,
|
||||
ksmc: name || "考试场次",
|
||||
};
|
||||
if (q.njmcId != null && String(q.njmcId).trim()) {
|
||||
try {
|
||||
kscc.value.njmcId = decodeURIComponent(String(q.njmcId));
|
||||
} catch {
|
||||
kscc.value.njmcId = String(q.njmcId);
|
||||
}
|
||||
}
|
||||
})
|
||||
|
||||
const kscjList = ref<any>([])
|
||||
const curKsdj = ref<any>({})
|
||||
|
||||
@ -234,76 +278,168 @@ const floatToInt = (floatNum: number, scale: number) => {
|
||||
return Math.round(floatNum * scale);
|
||||
}
|
||||
|
||||
let singleFlag = false;
|
||||
/** 与后端 KsccKmCjServiceImpl.matchRule 一致(initKsdj 后边界已为 scaled int) */
|
||||
function matchDjRule(score: number, boundary: unknown, rule: string | undefined): boolean {
|
||||
if (boundary === null || boundary === undefined || boundary === "") return true;
|
||||
const b = typeof boundary === "number" ? boundary : parseFloat(String(boundary));
|
||||
if (Number.isNaN(b)) return true;
|
||||
const r = rule != null ? String(rule).trim() : "";
|
||||
if (!r) return true;
|
||||
switch (r) {
|
||||
case ">=":
|
||||
return score >= b;
|
||||
case ">":
|
||||
return score > b;
|
||||
case "<=":
|
||||
return score <= b;
|
||||
case "<":
|
||||
return score < b;
|
||||
default:
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
// 初始化考试等级列表
|
||||
/** initKsdj 已将 kmDjList 的 zdf/zgf 转为与分数相同的 scale,此处用 scaled 分数匹配 */
|
||||
function resolveKmDjScaled(fs: number | null | undefined, kmId: string): any | null {
|
||||
if (fs === null || fs === undefined || Number.isNaN(Number(fs))) return null;
|
||||
const scoreScaled = floatToInt(Number(fs), fsScale);
|
||||
const listDj = kmDjList.value.filter((d: any) => String(d.kmId || "") === String(kmId));
|
||||
const hit = listDj.find((item: any) => {
|
||||
const zdfRule =
|
||||
item.zdfRule != null && String(item.zdfRule).trim() !== ""
|
||||
? String(item.zdfRule).trim()
|
||||
: ">=";
|
||||
const zgfRule =
|
||||
item.zgfRule != null && String(item.zgfRule).trim() !== ""
|
||||
? String(item.zgfRule).trim()
|
||||
: "<=";
|
||||
return (
|
||||
matchDjRule(scoreScaled, item.zdf, zdfRule) && matchDjRule(scoreScaled, item.zgf, zgfRule)
|
||||
);
|
||||
});
|
||||
return hit || null;
|
||||
}
|
||||
|
||||
/** 多场等级中取 sort 最优(数值越小越靠前)的一条 */
|
||||
function pickBestDjMatch(rows: any[], scoreScaled: number): any | null {
|
||||
const matches = rows.filter((item: any) => {
|
||||
const zdfRule =
|
||||
item.zdfRule != null && String(item.zdfRule).trim() !== ""
|
||||
? String(item.zdfRule).trim()
|
||||
: ">=";
|
||||
const zgfRule =
|
||||
item.zgfRule != null && String(item.zgfRule).trim() !== ""
|
||||
? String(item.zgfRule).trim()
|
||||
: "<=";
|
||||
return (
|
||||
matchDjRule(scoreScaled, item.zdf, zdfRule) && matchDjRule(scoreScaled, item.zgf, zgfRule)
|
||||
);
|
||||
});
|
||||
if (!matches.length) return null;
|
||||
return matches.reduce((best, cur) =>
|
||||
Number(cur.sort ?? 9999) < Number(best.sort ?? 9999) ? cur : best
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* 场次总等级(lx≠2):先将「本场得分之和」线性映射到教务 djList 的刻度上界(各档 zgf 最大值),
|
||||
* 再按 zdfRule/zgfRule 匹配。当场次等级按模板(如满分 400)配置而本场科目满分之和为 200 时,
|
||||
* 避免误判;刻度一致时不缩放。(与 zhxy-jsd kspj/detail.vue 一致)
|
||||
*/
|
||||
function resolveOverallKsDj(sumScaled: number, examFullMarksScaled: number): any {
|
||||
const ksDjRows = djList.value.filter((d: any) => String(d.lx || "") !== "2");
|
||||
if (!ksDjRows.length) return {};
|
||||
|
||||
let scoreForMatch = sumScaled;
|
||||
if (examFullMarksScaled > 0) {
|
||||
const maxZgfScaled = Math.max(0, ...ksDjRows.map((d: any) => Number(d.zgf) || 0));
|
||||
if (maxZgfScaled > 0 && maxZgfScaled !== examFullMarksScaled) {
|
||||
scoreForMatch = Math.round((sumScaled * maxZgfScaled) / examFullMarksScaled);
|
||||
}
|
||||
}
|
||||
|
||||
return pickBestDjMatch(ksDjRows, scoreForMatch) || {};
|
||||
}
|
||||
|
||||
// 初始化考试等级列表(与教师端 kspj/detail 一致)
|
||||
const initKsdj = () => {
|
||||
let maxDj = 0.0;
|
||||
let maxKmDj = 0.0;
|
||||
djList.value.forEach((ksdj: any) => {
|
||||
ksdj.zdf = floatToInt(ksdj.zdf, fsScale); // 等级最低分
|
||||
ksdj.zgf = floatToInt(ksdj.zgf, fsScale); // 等级最高分
|
||||
ksdj.djclr = colorMap[ksdj.dj] || ''; // 等级颜色
|
||||
maxDj = Math.max(maxDj, ksdj.zgf);
|
||||
ksdj.zdf = floatToInt(ksdj.zdf, fsScale);
|
||||
ksdj.zgf = floatToInt(ksdj.zgf, fsScale);
|
||||
ksdj.djclr = colorMap[ksdj.dj] || "";
|
||||
});
|
||||
kmDjList.value.forEach((kmdj: any) => {
|
||||
kmdj.zdf = floatToInt(kmdj.zdf, fsScale); // 等级最低分
|
||||
kmdj.zgf = floatToInt(kmdj.zgf, fsScale); // 等级最高分
|
||||
kmdj.djclr = colorMap[kmdj.dj] || ''; // 等级颜色
|
||||
maxKmDj = Math.max(maxKmDj, kmdj.zgf);
|
||||
kmdj.zdf = floatToInt(kmdj.zdf, fsScale);
|
||||
kmdj.zgf = floatToInt(kmdj.zgf, fsScale);
|
||||
kmdj.djclr = colorMap[kmdj.dj] || "";
|
||||
});
|
||||
singleFlag = maxDj < maxKmDj + 100;
|
||||
};
|
||||
|
||||
const rebuildData = () => {
|
||||
let ksfsList: any[] = [];
|
||||
let totalFs = 0.00;
|
||||
let totalFs = 0.0;
|
||||
totalKmFs.value = 0;
|
||||
|
||||
ksccKscjList.value = ksccKscjList.value.map((cj: any) => {
|
||||
ksfsList.push(cj.ksfs);
|
||||
totalFs += cj.ksfs;
|
||||
let fs = floatToInt(cj.ksfs, fsScale);
|
||||
cj.djclr = colorMap[cj.dj] || '';
|
||||
// 查询考试等级
|
||||
totalFs += Number(cj.ksfs) || 0;
|
||||
const djMissing = !cj.dj || String(cj.dj).trim() === "";
|
||||
if (djMissing && kmDjList.value.length > 0 && cj.kmId) {
|
||||
const resolved = resolveKmDjScaled(cj.ksfs, cj.kmId);
|
||||
if (resolved) {
|
||||
cj.dj = resolved.dj;
|
||||
cj.djBx = resolved.djBx;
|
||||
cj.djLx = resolved.djLx;
|
||||
}
|
||||
}
|
||||
cj.djclr = colorMap[cj.dj] || "";
|
||||
cj.km = ksccKmList.value.find((item: any) => item.kmId === cj.kmId) || {};
|
||||
return cj;
|
||||
});
|
||||
// 雷达图数据
|
||||
|
||||
radarData.categories = ksccKmList.value.map((item: any) => {
|
||||
totalKmFs.value += item.kmfs;
|
||||
totalKmFs.value += Number(item.kmfs) || 0;
|
||||
return item.kmmc;
|
||||
});
|
||||
radarData.series = [{ name: "分数", data: ksfsList }];
|
||||
// 当前成绩列表
|
||||
totalFs = floatToInt(totalFs, fsScale);
|
||||
if (singleFlag) {
|
||||
totalFs = totalFs / ksccKmList.value.length;
|
||||
}
|
||||
curKsdj.value = djList.value.find((item: any) => item.zdf <= totalFs && item.zgf >= totalFs) || {};
|
||||
}
|
||||
|
||||
const sumScaled = floatToInt(totalFs, fsScale);
|
||||
const examFullMarksScaled = floatToInt(totalKmFs.value, fsScale);
|
||||
curKsdj.value = resolveOverallKsDj(sumScaled, examFullMarksScaled);
|
||||
};
|
||||
|
||||
onMounted(async () => {
|
||||
pageLoading.value = true;
|
||||
try {
|
||||
curXs.value = getCurXs;
|
||||
kscc.value = getData;
|
||||
if (!ksccFromRoute.value) {
|
||||
kscc.value = getData || {};
|
||||
}
|
||||
const ksccId = kscc.value?.id;
|
||||
if (!ksccId) {
|
||||
uni.showToast({ title: "请先选择考试场次", icon: "none" });
|
||||
return;
|
||||
}
|
||||
const res = await xsKscjApi({
|
||||
xsId: getCurXs.id,
|
||||
ksccId: getData.id,
|
||||
njmcId: getData.njmcId
|
||||
ksccId,
|
||||
njmcId: kscc.value?.njmcId ?? "",
|
||||
});
|
||||
if (res.resultCode == 1) {
|
||||
sysKmList.value = res.result.kmList || [];
|
||||
ksccKmList.value = res.result.ksccKmList || [];
|
||||
kmDjList.value = res.result.kmDjList || [];
|
||||
djList.value = res.result.djList || [];
|
||||
ksccKscjList.value = res.result.ksccKscjList || [];
|
||||
const r = res.result || {};
|
||||
showXsFs.value = r.showFs !== false;
|
||||
sysKmList.value = r.kmList || [];
|
||||
ksccKmList.value = r.ksccKmList || [];
|
||||
kmDjList.value = r.kmDjList || [];
|
||||
djList.value = r.djList || [];
|
||||
ksccKscjList.value = r.ksccKscjList || [];
|
||||
initKsdj();
|
||||
rebuildData();
|
||||
}
|
||||
// 加载班主任寄语
|
||||
try {
|
||||
const pjRes = await ksccPjFindByKsccAndXsApi({
|
||||
ksccId: getData.id,
|
||||
ksccId,
|
||||
xsId: getCurXs.id,
|
||||
});
|
||||
if (pjRes && pjRes.resultCode === 1 && pjRes.result && pjRes.result.pjBzr) {
|
||||
|
||||
@ -1,132 +1,157 @@
|
||||
<template>
|
||||
<view class="ks-application-page">
|
||||
<BasicListLayout @register="register">
|
||||
<template v-slot="{ data }">
|
||||
<view class="ks-card" @click="viewDetails(data)">
|
||||
<view class="card-header">
|
||||
<text class="applicant-name"
|
||||
>{{ data.ksmc }}</text
|
||||
<view class="page">
|
||||
<view class="head-tip">请选择考试场次</view>
|
||||
<scroll-view scroll-y class="scroll">
|
||||
<view v-if="loading" class="state">加载中...</view>
|
||||
<view v-else-if="!treeData.length" class="state">暂无考试场次数据</view>
|
||||
<view v-else class="sections">
|
||||
<view v-for="xq in treeData" :key="xqKey(xq)" class="section">
|
||||
<text class="section-title">{{ xq.title || xq.label || "学期" }}</text>
|
||||
<view
|
||||
v-for="c in xq.children || []"
|
||||
:key="ksccKey(c)"
|
||||
class="kscc-row"
|
||||
@click="goDetail(xq, c)"
|
||||
>
|
||||
<text class="kscc-name">{{ c.title || c.ksmc || "—" }}</text>
|
||||
<text class="arrow">›</text>
|
||||
</view>
|
||||
<view class="card-body">
|
||||
<view class="info-row">
|
||||
<text class="label">考试科目:</text>
|
||||
<text class="value">{{ data.kmmc }}</text>
|
||||
</view>
|
||||
<view class="info-row">
|
||||
<text class="label">开始时间:</text>
|
||||
<text class="value">{{ data.kskstime }}</text>
|
||||
</view>
|
||||
<view class="info-row">
|
||||
<text class="label">结束时间:</text>
|
||||
<text class="value">{{ data.ksjstime }}</text>
|
||||
<view v-if="!(xq.children || []).length" class="kscc-empty">该学期下暂无场次</view>
|
||||
</view>
|
||||
</view>
|
||||
<view class="card-footer">
|
||||
<text>查看详情</text>
|
||||
<text class="arrow">
|
||||
<uni-icons type="arrowright" size="16" color="#ccc"></uni-icons>
|
||||
</text>
|
||||
</view>
|
||||
</view>
|
||||
</template>
|
||||
</BasicListLayout>
|
||||
</scroll-view>
|
||||
</view>
|
||||
</template>
|
||||
|
||||
<script setup lang="ts">
|
||||
import { ref } from "vue";
|
||||
import { useLayout } from "@/components/BasicListLayout/hooks/useLayout";
|
||||
import { xsKsccApi } from "@/api/base/server";
|
||||
import { ref, onMounted } from "vue";
|
||||
import { onPullDownRefresh } from "@dcloudio/uni-app";
|
||||
import { ksccFindAllXqKsccTreeApi } from "@/api/base/server";
|
||||
import { useUserStore } from "@/store/modules/user";
|
||||
import { useDataStore } from "@/store/modules/data";
|
||||
|
||||
const { getCurXs } = useUserStore();
|
||||
const { setData } = useDataStore();
|
||||
|
||||
let pageParams = ref({
|
||||
rows: 10,
|
||||
xsId: getCurXs.id
|
||||
})
|
||||
const loading = ref(true);
|
||||
const treeData = ref<any[]>([]);
|
||||
|
||||
const [register, { reload }] = useLayout({
|
||||
api: xsKsccApi,
|
||||
componentProps: {},
|
||||
param: pageParams.value
|
||||
function xqKey(xq: any) {
|
||||
return String(xq.key ?? xq.id ?? xq.title ?? "");
|
||||
}
|
||||
|
||||
function ksccKey(c: any) {
|
||||
return String(c.key ?? c.id ?? c.title ?? "");
|
||||
}
|
||||
|
||||
async function loadTree() {
|
||||
loading.value = true;
|
||||
try {
|
||||
const xs = getCurXs as any;
|
||||
const bjId = xs?.bjId ?? xs?.bj_id;
|
||||
const res: any = await ksccFindAllXqKsccTreeApi(
|
||||
bjId ? { bjId: String(bjId).trim() } : {}
|
||||
);
|
||||
const raw = res?.result ?? res?.rows ?? res?.data ?? res;
|
||||
treeData.value = Array.isArray(raw) ? raw : [];
|
||||
} catch {
|
||||
treeData.value = [];
|
||||
} finally {
|
||||
loading.value = false;
|
||||
}
|
||||
}
|
||||
|
||||
function goDetail(xq: any, c: any) {
|
||||
const ksccId = c?.key ?? c?.id;
|
||||
if (!ksccId) {
|
||||
uni.showToast({ title: "场次ID无效", icon: "none" });
|
||||
return;
|
||||
}
|
||||
const xqTitle = String(xq?.title ?? xq?.label ?? "").trim();
|
||||
const ksTitle = String(c?.title ?? c?.ksmc ?? "").trim();
|
||||
const idEnc = encodeURIComponent(String(ksccId));
|
||||
const ksEnc = encodeURIComponent(ksTitle || "考试场次");
|
||||
uni.navigateTo({
|
||||
url: `/pages/base/grades/detail?ksccId=${idEnc}&ksmc=${ksEnc}`,
|
||||
});
|
||||
}
|
||||
|
||||
onMounted(() => {
|
||||
void loadTree();
|
||||
});
|
||||
|
||||
// 查看详情或新增处理函数
|
||||
const viewDetails = (item: any | null) => {
|
||||
setData(item);
|
||||
uni.navigateTo({ url: '/pages/base/grades/detail' });
|
||||
};
|
||||
onPullDownRefresh(() => {
|
||||
void loadTree().finally(() => uni.stopPullDownRefresh());
|
||||
});
|
||||
</script>
|
||||
|
||||
<style lang="scss" scoped>
|
||||
.ks-card {
|
||||
background-color: #ffffff;
|
||||
border-radius: 8px;
|
||||
margin-bottom: 15px;
|
||||
box-shadow: 0 2px 6px rgba(0, 0, 0, 0.08);
|
||||
overflow: hidden;
|
||||
}
|
||||
|
||||
.card-header {
|
||||
padding: 12px 15px;
|
||||
border-bottom: 1px solid #f0f0f0;
|
||||
.applicant-name {
|
||||
font-size: 16px;
|
||||
font-weight: bold;
|
||||
color: #333;
|
||||
}
|
||||
}
|
||||
|
||||
.card-body {
|
||||
padding: 15px;
|
||||
.info-row {
|
||||
.page {
|
||||
min-height: 100vh;
|
||||
height: 100vh;
|
||||
display: flex;
|
||||
margin-bottom: 10px;
|
||||
&:last-child {
|
||||
margin-bottom: 0;
|
||||
flex-direction: column;
|
||||
background: #f1f5f9;
|
||||
box-sizing: border-box;
|
||||
}
|
||||
.label {
|
||||
font-size: 14px;
|
||||
color: #666;
|
||||
width: 70px;
|
||||
.head-tip {
|
||||
padding: 20rpx 24rpx 12rpx;
|
||||
font-size: 26rpx;
|
||||
color: #64748b;
|
||||
background: #f8fafc;
|
||||
border-bottom: 1rpx solid #e2e8f0;
|
||||
flex-shrink: 0;
|
||||
margin-right: 8px;
|
||||
}
|
||||
.value {
|
||||
font-size: 14px;
|
||||
color: #333;
|
||||
.scroll {
|
||||
flex: 1;
|
||||
min-height: 0;
|
||||
height: 0;
|
||||
box-sizing: border-box;
|
||||
}
|
||||
.sections {
|
||||
padding: 16rpx 24rpx 40rpx;
|
||||
}
|
||||
.section {
|
||||
margin-bottom: 28rpx;
|
||||
}
|
||||
|
||||
.card-footer {
|
||||
padding: 12px 15px;
|
||||
border-top: 1px solid #f0f0f0;
|
||||
.section-title {
|
||||
display: block;
|
||||
font-size: 28rpx;
|
||||
font-weight: 600;
|
||||
color: #334155;
|
||||
margin-bottom: 12rpx;
|
||||
padding-left: 4rpx;
|
||||
}
|
||||
.kscc-row {
|
||||
display: flex;
|
||||
justify-content: space-between;
|
||||
align-items: center;
|
||||
font-size: 14px;
|
||||
color: #888;
|
||||
cursor: pointer;
|
||||
|
||||
justify-content: space-between;
|
||||
padding: 28rpx 24rpx;
|
||||
margin-bottom: 12rpx;
|
||||
background: #fff;
|
||||
border-radius: 16rpx;
|
||||
border: 1rpx solid #e2e8f0;
|
||||
box-shadow: 0 2rpx 8rpx rgba(15, 23, 42, 0.04);
|
||||
}
|
||||
.kscc-name {
|
||||
flex: 1;
|
||||
min-width: 0;
|
||||
font-size: 30rpx;
|
||||
color: #0f172a;
|
||||
padding-right: 16rpx;
|
||||
}
|
||||
.arrow {
|
||||
font-size: 16px;
|
||||
color: #ccc;
|
||||
font-size: 36rpx;
|
||||
color: #94a3b8;
|
||||
font-weight: 300;
|
||||
}
|
||||
.kscc-empty {
|
||||
font-size: 26rpx;
|
||||
color: #94a3b8;
|
||||
padding: 16rpx 8rpx;
|
||||
}
|
||||
|
||||
// 新增按钮样式示例 (可根据 BasicListLayout 的 bottom 插槽调整)
|
||||
.button {
|
||||
padding: 10px 15px;
|
||||
background-color: #447ade;
|
||||
color: white;
|
||||
.state {
|
||||
text-align: center;
|
||||
border-radius: 5px;
|
||||
margin: 10px 15px; // 示例外边距
|
||||
font-size: 16px;
|
||||
color: #64748b;
|
||||
padding: 80rpx 24rpx;
|
||||
font-size: 28rpx;
|
||||
}
|
||||
</style>
|
||||
@ -14,24 +14,27 @@
|
||||
<view class="page-banner">
|
||||
<view class="banner-content">
|
||||
<view class="banner-title-wrapper">
|
||||
<text class="banner-icon">📝</text>
|
||||
<text class="banner-icon">{{ activeTab === 0 ? '📝' : '📚' }}</text>
|
||||
<view class="banner-text">
|
||||
<text class="banner-title">作品任务</text>
|
||||
<text class="banner-subtitle">独立项目选择 · 学习成长</text>
|
||||
<text class="banner-title">{{ activeTab === 0 ? '作品任务' : '作品资源' }}</text>
|
||||
<text class="banner-subtitle">{{
|
||||
activeTab === 0 ? '独立项目选择 · 学习成长' : '课程资料 · 在线查看'
|
||||
}}</text>
|
||||
</view>
|
||||
</view>
|
||||
<view class="task-count">
|
||||
<text class="count-number">{{ taskList.length }}</text>
|
||||
<text class="count-label">个任务</text>
|
||||
<text class="count-number">{{ activeTab === 0 ? submitTasks.length : resourceTasks.length }}</text>
|
||||
<text class="count-label">{{ activeTab === 0 ? '个任务' : '项资源' }}</text>
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
|
||||
<!-- 独立项目选择提示 -->
|
||||
<view class="selection-tip" v-if="taskList.length > 0">
|
||||
<view class="tip-content">
|
||||
<text class="tip-title">独立项目选择</text>
|
||||
<text class="tip-desc">请从下方{{ taskList.length }}个任务中选择1个完成,可自主挑战更高层级</text>
|
||||
<view class="tab-bar">
|
||||
<view class="tab-item" :class="{ active: activeTab === 0 }" @click="activeTab = 0">
|
||||
<text class="tab-text">作品任务</text>
|
||||
</view>
|
||||
<view class="tab-item" :class="{ active: activeTab === 1 }" @click="activeTab = 1">
|
||||
<text class="tab-text">作品资源</text>
|
||||
</view>
|
||||
</view>
|
||||
|
||||
@ -42,16 +45,18 @@
|
||||
<text class="loading-text">加载中...</text>
|
||||
</view>
|
||||
|
||||
<template v-else-if="taskList.length > 0">
|
||||
<template v-else-if="displayList.length > 0">
|
||||
<view
|
||||
v-for="task in taskList"
|
||||
v-for="task in displayList"
|
||||
:key="task.id"
|
||||
class="task-card"
|
||||
:class="{ 'task-card--resource': activeTab === 1 }"
|
||||
@click="onTaskCardClick(task)"
|
||||
>
|
||||
<view class="card-header">
|
||||
<view class="header-left">
|
||||
<view class="task-icon">📝</view>
|
||||
<text class="task-title">{{ task.zpmc || '作品任务' }}</text>
|
||||
<view class="task-icon">{{ activeTab === 0 ? '📝' : '📚' }}</view>
|
||||
<text class="task-title">{{ task.zpmc || (activeTab === 0 ? '作品任务' : '作品资料') }}</text>
|
||||
</view>
|
||||
<view class="status-badge" :class="getStatusClass(task.zpzt)">
|
||||
<text class="status-text">{{ getStatusText(task.zpzt) }}</text>
|
||||
@ -76,11 +81,15 @@
|
||||
</view>
|
||||
|
||||
<view class="card-footer">
|
||||
<button class="action-btn challenge-btn" @click.stop="startChallenge(task)">
|
||||
<button
|
||||
v-if="activeTab === 0"
|
||||
class="action-btn challenge-btn"
|
||||
@click.stop="startChallenge(task)"
|
||||
>
|
||||
开始挑战
|
||||
</button>
|
||||
<button class="action-btn detail-btn" @click.stop="viewTaskDetail(task)">
|
||||
详情
|
||||
<button class="action-btn detail-btn" @click.stop="activeTab === 0 ? viewTaskDetail(task) : viewResourceDetail(task)">
|
||||
{{ activeTab === 0 ? '详情' : '查看资料' }}
|
||||
</button>
|
||||
</view>
|
||||
</view>
|
||||
@ -88,7 +97,7 @@
|
||||
|
||||
<view v-else class="empty-state">
|
||||
<view class="empty-icon">📭</view>
|
||||
<text class="empty-text">暂无作品任务</text>
|
||||
<text class="empty-text">{{ activeTab === 0 ? '暂无作品任务' : '暂无作品资源' }}</text>
|
||||
</view>
|
||||
</scroll-view>
|
||||
</view>
|
||||
@ -96,7 +105,7 @@
|
||||
</template>
|
||||
|
||||
<script lang="ts" setup>
|
||||
import { ref, onMounted, onUnmounted } from "vue";
|
||||
import { ref, computed, onUnmounted } from "vue";
|
||||
import { onShow, onLoad } from "@dcloudio/uni-app";
|
||||
import { useUserStore } from "@/store/modules/user";
|
||||
import { zpzxFindByKcParamsApi } from "@/api/base/server";
|
||||
@ -114,9 +123,21 @@ interface TaskItem {
|
||||
kcId?: string;
|
||||
xsId?: string;
|
||||
ispj?: string; // A:已评价 B:未评价(待评价)
|
||||
/** SUBMIT 任务提交,VIEW 资料查看 */
|
||||
rwms?: string;
|
||||
}
|
||||
|
||||
const taskList = ref<TaskItem[]>([]);
|
||||
const activeTab = ref(0);
|
||||
|
||||
const isResourceTask = (t: TaskItem) =>
|
||||
t.rwms != null && String(t.rwms).trim().toUpperCase() === "VIEW";
|
||||
|
||||
const submitTasks = computed(() => taskList.value.filter((t) => !isResourceTask(t)));
|
||||
const resourceTasks = computed(() => taskList.value.filter((t) => isResourceTask(t)));
|
||||
const displayList = computed(() =>
|
||||
activeTab.value === 0 ? submitTasks.value : resourceTasks.value
|
||||
);
|
||||
const isLoading = ref(false);
|
||||
const kcId = ref<string>('');
|
||||
const xsId = ref<string>('');
|
||||
@ -252,7 +273,7 @@ const startChallenge = (task: TaskItem) => {
|
||||
}
|
||||
|
||||
// 仅当存在「另一任务已提交且已被评价」时才禁止换项;已提交但 ispj=B(待评价)时仍可点击开始挑战
|
||||
const otherLocked = taskList.value.find(
|
||||
const otherLocked = submitTasks.value.find(
|
||||
(t) => t.id !== task.id && isTaskEvaluated(t)
|
||||
);
|
||||
if (otherLocked) {
|
||||
@ -284,7 +305,7 @@ const startChallenge = (task: TaskItem) => {
|
||||
});
|
||||
};
|
||||
|
||||
// 查看详情 - 跳转到详情页面
|
||||
// 查看详情 - 跳转到任务详情页
|
||||
const viewTaskDetail = (task: TaskItem) => {
|
||||
const params = new URLSearchParams();
|
||||
params.append('zpId', task.zpId);
|
||||
@ -299,6 +320,27 @@ const viewTaskDetail = (task: TaskItem) => {
|
||||
});
|
||||
};
|
||||
|
||||
/** 作品资源(资料查看)详情 */
|
||||
const viewResourceDetail = (task: TaskItem) => {
|
||||
const params = new URLSearchParams();
|
||||
params.append('zpId', task.zpId);
|
||||
if (task.kcId || kcId.value) {
|
||||
params.append('kcId', task.kcId || kcId.value);
|
||||
}
|
||||
if (task.xsId || xsId.value) {
|
||||
params.append('xsId', task.xsId || xsId.value);
|
||||
}
|
||||
uni.navigateTo({
|
||||
url: `/pages/base/xszp/resource-detail?${params.toString()}`
|
||||
});
|
||||
};
|
||||
|
||||
const onTaskCardClick = (task: TaskItem) => {
|
||||
if (activeTab.value === 1) {
|
||||
viewResourceDetail(task);
|
||||
}
|
||||
};
|
||||
|
||||
const getStatusClass = (status: string) => {
|
||||
switch (status) {
|
||||
case 'A':
|
||||
@ -413,33 +455,37 @@ const formatTime = (timeStr?: string) => {
|
||||
}
|
||||
}
|
||||
|
||||
// 独立项目选择提示样式
|
||||
.selection-tip {
|
||||
background: linear-gradient(135deg, #e6f4ff 0%, #f0f8ff 100%);
|
||||
margin: 0;
|
||||
padding: 16px;
|
||||
box-shadow: 0 2px 8px rgba(78, 115, 223, 0.1);
|
||||
|
||||
.tip-content {
|
||||
.tab-bar {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
gap: 6px;
|
||||
text-align: center;
|
||||
|
||||
.tip-title {
|
||||
font-size: 17px;
|
||||
font-weight: 700;
|
||||
color: #2c3e50;
|
||||
line-height: 1.4;
|
||||
background: #ffffff;
|
||||
margin: 0 16px;
|
||||
margin-top: -10px;
|
||||
margin-bottom: 12px;
|
||||
border-radius: 12px;
|
||||
padding: 4px;
|
||||
box-shadow: 0 2px 12px rgba(0, 0, 0, 0.08);
|
||||
position: relative;
|
||||
z-index: 2;
|
||||
}
|
||||
|
||||
.tip-desc {
|
||||
font-size: 14px;
|
||||
color: #4e73df;
|
||||
line-height: 1.5;
|
||||
font-weight: 500;
|
||||
.tab-item {
|
||||
flex: 1;
|
||||
text-align: center;
|
||||
padding: 10px 0;
|
||||
border-radius: 10px;
|
||||
transition: background 0.2s ease, color 0.2s ease;
|
||||
|
||||
.tab-text {
|
||||
font-size: 15px;
|
||||
color: #666;
|
||||
}
|
||||
|
||||
&.active {
|
||||
background: linear-gradient(135deg, #4e73df 0%, #2e59d9 100%);
|
||||
|
||||
.tab-text {
|
||||
color: #ffffff;
|
||||
font-weight: 600;
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -489,6 +535,10 @@ const formatTime = (timeStr?: string) => {
|
||||
position: relative;
|
||||
overflow: visible;
|
||||
|
||||
&--resource {
|
||||
cursor: pointer;
|
||||
}
|
||||
|
||||
&:active {
|
||||
transform: translateY(2px) scale(0.98);
|
||||
box-shadow:
|
||||
|
||||
445
src/pages/base/xszp/resource-detail.vue
Normal file
445
src/pages/base/xszp/resource-detail.vue
Normal file
@ -0,0 +1,445 @@
|
||||
<!-- 作品资源详情(资料查看) -->
|
||||
<template>
|
||||
<BasicLayout>
|
||||
<view class="task-detail-page">
|
||||
<view v-if="isLoading" class="loading-indicator">
|
||||
<view class="loading-spinner"></view>
|
||||
<text class="loading-text">加载中...</text>
|
||||
</view>
|
||||
|
||||
<view v-else class="content-wrapper">
|
||||
<view class="page-inner">
|
||||
<view class="resource-meta-card">
|
||||
<view class="meta-card-title">资源内容</view>
|
||||
|
||||
<view class="meta-block">
|
||||
<text class="meta-label">资源名称</text>
|
||||
<text class="meta-value meta-value--title">{{ taskInfo.zpmc || '作品资料' }}</text>
|
||||
</view>
|
||||
|
||||
<view v-if="taskInfo.zpms" class="meta-block meta-block--desc">
|
||||
<text class="meta-label">资源描述</text>
|
||||
<text class="meta-value meta-value--body">{{ taskInfo.zpms }}</text>
|
||||
</view>
|
||||
</view>
|
||||
|
||||
<view v-if="taskInfo.fileUrl" class="attachment-card">
|
||||
<view class="attachment-card-head">
|
||||
<text class="attachment-icon">📎</text>
|
||||
<view class="attachment-head-texts">
|
||||
<text class="attachment-title">附件资料</text>
|
||||
<text class="attachment-hint">点击下方文件名称,即可预览或下载</text>
|
||||
</view>
|
||||
</view>
|
||||
<view class="attachment-body">
|
||||
<BasicFilePreview
|
||||
:file-url="taskInfo.fileUrl"
|
||||
:file-name="taskInfo.fileName"
|
||||
:file-format="taskInfo.fileFormat"
|
||||
/>
|
||||
</view>
|
||||
</view>
|
||||
|
||||
<view v-if="taskItemList.length > 0" class="task-items-section">
|
||||
<view class="section-title">附加说明</view>
|
||||
|
||||
<view
|
||||
v-for="(item, index) in taskItemList"
|
||||
:key="item.id || index"
|
||||
class="task-item-card"
|
||||
>
|
||||
<view class="item-header">
|
||||
<text class="item-number">{{ index + 1 }}</text>
|
||||
<text class="item-title">{{ item.zpbt || '说明' }}</text>
|
||||
<view v-if="item.isbt === 1 || item.isbt === true" class="required-badge">
|
||||
<text class="required-text">必填</text>
|
||||
</view>
|
||||
</view>
|
||||
|
||||
<view v-if="item.remark" class="item-remark">
|
||||
<text class="remark-text">{{ item.remark }}</text>
|
||||
</view>
|
||||
|
||||
<view class="item-type">
|
||||
<text class="type-label">类型:</text>
|
||||
<text class="type-value">{{ getTaskTypeText(item.zpfl) }}</text>
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
</BasicLayout>
|
||||
</template>
|
||||
|
||||
<script lang="ts" setup>
|
||||
import { ref } from 'vue';
|
||||
import { onLoad } from '@dcloudio/uni-app';
|
||||
import { zpFindDetailByIdApi } from "@/api/base/server";
|
||||
import BasicFilePreview from "@/components/BasicFile/preview.vue";
|
||||
|
||||
interface TaskInfo {
|
||||
id?: string;
|
||||
zpmc?: string;
|
||||
zpms?: string;
|
||||
zpkstime?: string;
|
||||
zpjstime?: string;
|
||||
fileUrl?: string;
|
||||
fileName?: string;
|
||||
fileFormat?: string;
|
||||
[key: string]: any;
|
||||
}
|
||||
|
||||
interface TaskItem {
|
||||
id: string;
|
||||
zpbt?: string;
|
||||
zpfl?: string;
|
||||
isbt?: number | boolean;
|
||||
remark?: string;
|
||||
zpfldm?: string;
|
||||
[key: string]: any;
|
||||
}
|
||||
|
||||
const isLoading = ref(false);
|
||||
const taskInfo = ref<TaskInfo>({});
|
||||
const taskItemList = ref<TaskItem[]>([]);
|
||||
|
||||
onLoad(async (options) => {
|
||||
const zpId = options?.zpId || '';
|
||||
|
||||
if (!zpId) {
|
||||
uni.showToast({ title: '缺少资源编号', icon: 'error' });
|
||||
setTimeout(() => {
|
||||
uni.navigateBack();
|
||||
}, 1500);
|
||||
return;
|
||||
}
|
||||
|
||||
await loadResourceDetail(zpId);
|
||||
});
|
||||
|
||||
const loadResourceDetail = async (zpId: string) => {
|
||||
try {
|
||||
isLoading.value = true;
|
||||
|
||||
const response: any = await zpFindDetailByIdApi({ id: zpId });
|
||||
const detailData = response?.result || response?.data || response;
|
||||
|
||||
if (!detailData) {
|
||||
throw new Error('未找到资料');
|
||||
}
|
||||
|
||||
const zpData = detailData.zp || {};
|
||||
taskInfo.value = zpData;
|
||||
taskItemList.value = detailData.zplxList || [];
|
||||
|
||||
} catch (error) {
|
||||
console.error('加载资源详情失败:', error);
|
||||
uni.showToast({
|
||||
title: error instanceof Error ? error.message : '加载失败,请重试',
|
||||
icon: 'error'
|
||||
});
|
||||
} finally {
|
||||
isLoading.value = false;
|
||||
}
|
||||
};
|
||||
|
||||
const getTaskTypeText = (type?: string) => {
|
||||
const typeMap: Record<string, string> = {
|
||||
'sctp': '上传图片',
|
||||
'scsp': '上传视频',
|
||||
'scwd': '上传文档',
|
||||
'fwb': '富文本',
|
||||
'text': '文本',
|
||||
'dxsx': '多项选择',
|
||||
'dxxz': '单项选择'
|
||||
};
|
||||
return typeMap[type || ''] || '未知类型';
|
||||
};
|
||||
</script>
|
||||
|
||||
<style scoped lang="scss">
|
||||
.task-detail-page {
|
||||
background: linear-gradient(180deg, #eef2fb 0%, #f4f5f7 120px, #f4f5f7 100%);
|
||||
min-height: 100vh;
|
||||
}
|
||||
|
||||
.loading-indicator {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
padding: 40px 0;
|
||||
|
||||
.loading-spinner {
|
||||
width: 40px;
|
||||
height: 40px;
|
||||
border: 3px solid #f3f3f3;
|
||||
border-top: 3px solid #4e73df;
|
||||
border-radius: 50%;
|
||||
animation: spin 1s linear infinite;
|
||||
margin-bottom: 10px;
|
||||
}
|
||||
|
||||
.loading-text {
|
||||
color: #999;
|
||||
font-size: 14px;
|
||||
}
|
||||
}
|
||||
|
||||
@keyframes spin {
|
||||
0% { transform: rotate(0deg); }
|
||||
100% { transform: rotate(360deg); }
|
||||
}
|
||||
|
||||
.content-wrapper {
|
||||
padding-bottom: 24px;
|
||||
}
|
||||
|
||||
.page-inner {
|
||||
padding: 16px;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
gap: 16px;
|
||||
}
|
||||
|
||||
.resource-meta-card {
|
||||
padding: 18px 16px;
|
||||
background: #fff;
|
||||
border-radius: 14px;
|
||||
box-shadow: 0 4px 20px rgba(46, 89, 217, 0.08);
|
||||
border: 1px solid rgba(78, 115, 223, 0.12);
|
||||
}
|
||||
|
||||
.meta-card-title {
|
||||
font-size: 17px;
|
||||
font-weight: 700;
|
||||
color: #1a1a2e;
|
||||
margin-bottom: 14px;
|
||||
padding-bottom: 10px;
|
||||
border-bottom: 2px solid #4e73df;
|
||||
}
|
||||
|
||||
.meta-block {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
gap: 6px;
|
||||
margin-bottom: 16px;
|
||||
|
||||
&:last-child {
|
||||
margin-bottom: 0;
|
||||
}
|
||||
|
||||
&--desc {
|
||||
padding-top: 4px;
|
||||
border-top: 1px solid #f0f2f5;
|
||||
}
|
||||
}
|
||||
|
||||
.meta-label {
|
||||
font-size: 13px;
|
||||
color: #6b7280;
|
||||
font-weight: 500;
|
||||
}
|
||||
|
||||
.meta-value {
|
||||
color: #374151;
|
||||
word-break: break-word;
|
||||
|
||||
&--title {
|
||||
font-size: 18px;
|
||||
font-weight: 700;
|
||||
color: #111827;
|
||||
line-height: 1.4;
|
||||
}
|
||||
|
||||
&--body {
|
||||
font-size: 15px;
|
||||
line-height: 1.7;
|
||||
color: #4b5563;
|
||||
}
|
||||
}
|
||||
|
||||
.attachment-card {
|
||||
background: linear-gradient(145deg, #ffffff 0%, #f8faff 100%);
|
||||
border-radius: 14px;
|
||||
border: 1px solid rgba(78, 115, 223, 0.22);
|
||||
box-shadow: 0 6px 24px rgba(46, 89, 217, 0.12);
|
||||
overflow: hidden;
|
||||
}
|
||||
|
||||
.attachment-card-head {
|
||||
display: flex;
|
||||
align-items: flex-start;
|
||||
gap: 12px;
|
||||
padding: 16px 16px 12px;
|
||||
background: linear-gradient(135deg, rgba(78, 115, 223, 0.1) 0%, rgba(78, 115, 223, 0.02) 100%);
|
||||
}
|
||||
|
||||
.attachment-icon {
|
||||
font-size: 28px;
|
||||
line-height: 1;
|
||||
}
|
||||
|
||||
.attachment-head-texts {
|
||||
flex: 1;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
gap: 6px;
|
||||
}
|
||||
|
||||
.attachment-title {
|
||||
font-size: 17px;
|
||||
font-weight: 700;
|
||||
color: #1e3a5f;
|
||||
}
|
||||
|
||||
.attachment-hint {
|
||||
font-size: 13px;
|
||||
color: #5c6b8a;
|
||||
line-height: 1.45;
|
||||
}
|
||||
|
||||
.attachment-body {
|
||||
padding: 8px 12px 16px;
|
||||
}
|
||||
|
||||
.task-items-section {
|
||||
padding: 18px 16px;
|
||||
background: #fff;
|
||||
border-radius: 14px;
|
||||
box-shadow: 0 4px 20px rgba(46, 89, 217, 0.06);
|
||||
border: 1px solid rgba(0, 0, 0, 0.06);
|
||||
|
||||
.section-title {
|
||||
font-size: 16px;
|
||||
font-weight: bold;
|
||||
margin-bottom: 15px;
|
||||
color: #333;
|
||||
border-bottom: 2px solid #4e73df;
|
||||
padding-bottom: 5px;
|
||||
}
|
||||
|
||||
.task-item-card {
|
||||
padding: 12px;
|
||||
margin-bottom: 12px;
|
||||
background: #f8f9fa;
|
||||
border-radius: 8px;
|
||||
border-left: 3px solid #4e73df;
|
||||
|
||||
&:last-child {
|
||||
margin-bottom: 0;
|
||||
}
|
||||
|
||||
.item-header {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
margin-bottom: 8px;
|
||||
|
||||
.item-number {
|
||||
width: 24px;
|
||||
height: 24px;
|
||||
line-height: 24px;
|
||||
text-align: center;
|
||||
background: #4e73df;
|
||||
color: #fff;
|
||||
border-radius: 50%;
|
||||
font-size: 12px;
|
||||
font-weight: bold;
|
||||
margin-right: 8px;
|
||||
flex-shrink: 0;
|
||||
}
|
||||
|
||||
.item-title {
|
||||
flex: 1;
|
||||
font-size: 15px;
|
||||
font-weight: 600;
|
||||
color: #333;
|
||||
}
|
||||
|
||||
.required-badge {
|
||||
padding: 2px 8px;
|
||||
background: #fff3cd;
|
||||
color: #856404;
|
||||
border-radius: 4px;
|
||||
font-size: 11px;
|
||||
margin-left: 8px;
|
||||
|
||||
.required-text {
|
||||
font-weight: 500;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.item-remark {
|
||||
margin-bottom: 8px;
|
||||
padding-left: 32px;
|
||||
|
||||
.remark-text {
|
||||
font-size: 13px;
|
||||
color: #666;
|
||||
line-height: 1.5;
|
||||
}
|
||||
}
|
||||
|
||||
.item-type {
|
||||
padding-left: 32px;
|
||||
font-size: 13px;
|
||||
|
||||
.type-label {
|
||||
color: #999;
|
||||
}
|
||||
|
||||
.type-value {
|
||||
color: #4e73df;
|
||||
font-weight: 500;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/* 放大附件列表点击区域与字号,便于查阅 */
|
||||
.attachment-body :deep(.basic-file-preview .file-list) {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
gap: 12px;
|
||||
}
|
||||
|
||||
.attachment-body :deep(.basic-file-preview .file-item) {
|
||||
display: flex;
|
||||
flex-direction: row;
|
||||
align-items: center;
|
||||
margin-bottom: 0;
|
||||
padding: 14px 16px;
|
||||
background: #fff;
|
||||
border-radius: 12px;
|
||||
border: 1px solid #e5e7eb;
|
||||
box-shadow: 0 2px 8px rgba(0, 0, 0, 0.04);
|
||||
min-height: 52px;
|
||||
}
|
||||
|
||||
.attachment-body :deep(.basic-file-preview .file-item:active) {
|
||||
background: #f3f4f6;
|
||||
}
|
||||
|
||||
.attachment-body :deep(.basic-file-preview .file-label) {
|
||||
font-size: 14px;
|
||||
color: #6b7280;
|
||||
margin-right: 10px;
|
||||
font-weight: 500;
|
||||
}
|
||||
|
||||
.attachment-body :deep(.basic-file-preview .file-name) {
|
||||
font-size: 16px;
|
||||
font-weight: 600;
|
||||
line-height: 1.5;
|
||||
padding: 4px 0;
|
||||
color: #2563eb;
|
||||
text-decoration: none;
|
||||
border-bottom: 1px solid rgba(37, 99, 235, 0.35);
|
||||
}
|
||||
|
||||
.attachment-body :deep(.basic-file-preview .file-name:active) {
|
||||
color: #1d4ed8;
|
||||
}
|
||||
</style>
|
||||
Loading…
x
Reference in New Issue
Block a user