增加了手机操作端
This commit is contained in:
705
work-app/src/pages/task/detail.vue
Normal file
705
work-app/src/pages/task/detail.vue
Normal file
@@ -0,0 +1,705 @@
|
||||
<script setup lang="ts">
|
||||
import { computed, reactive, ref } from "vue";
|
||||
import { onLoad, onShow } from "@dcloudio/uni-app";
|
||||
import { adminApi, type AdminAppraisalTaskDetail, type AdminFileAsset } from "../../api/admin";
|
||||
import { showErrorToast, showInfoToast, withLoading } from "../../utils/feedback";
|
||||
|
||||
const loading = ref(false);
|
||||
const submitting = ref(false);
|
||||
const supplementSubmitting = ref(false);
|
||||
const uploading = ref(false);
|
||||
const pageReady = ref(false);
|
||||
const loadError = ref("");
|
||||
const detail = ref<AdminAppraisalTaskDetail | null>(null);
|
||||
const taskId = ref(0);
|
||||
const activeSection = ref<"result" | "supplement" | "zhongjian">("result");
|
||||
|
||||
const resultText = ref("");
|
||||
const resultDesc = ref("");
|
||||
const conditionGrade = ref("");
|
||||
const conditionDesc = ref("");
|
||||
const valuationMin = ref("");
|
||||
const valuationMax = ref("");
|
||||
const valuationDesc = ref("");
|
||||
const externalRemark = ref("");
|
||||
const internalRemark = ref("");
|
||||
const zhongjianReportNo = ref("");
|
||||
const zhongjianFiles = ref<AdminFileAsset[]>([]);
|
||||
const evidenceFiles = ref<AdminFileAsset[]>([]);
|
||||
const supplementForm = reactive({
|
||||
reason: "",
|
||||
deadline: "",
|
||||
items: [{ item_name: "", guide_text: "", is_required: true }],
|
||||
});
|
||||
|
||||
const isZhongjian = computed(() => detail.value?.task_info.service_provider === "zhongjian");
|
||||
const resultSummary = computed(() => detail.value?.result_info.result_text || "暂未填写");
|
||||
const reportSummary = computed(() => detail.value?.report_summary?.report_no || "");
|
||||
type AppraisalTemplate = NonNullable<AdminAppraisalTaskDetail["appraisal_template"]>;
|
||||
|
||||
function hasConditionFields(template?: AppraisalTemplate | null) {
|
||||
return (template?.condition_options?.length || 0) > 0;
|
||||
}
|
||||
|
||||
function hasValuationFields(template?: AppraisalTemplate | null) {
|
||||
return Boolean((template?.valuation_hint || "").trim());
|
||||
}
|
||||
|
||||
const showConditionFields = computed(() => hasConditionFields(detail.value?.appraisal_template));
|
||||
const showValuationFields = computed(() => hasValuationFields(detail.value?.appraisal_template));
|
||||
|
||||
function formatMoneyInput(value: string | number) {
|
||||
const num = Number(value || 0);
|
||||
return Number.isFinite(num) ? num : 0;
|
||||
}
|
||||
|
||||
function hydrate(detailData: AdminAppraisalTaskDetail) {
|
||||
detail.value = detailData;
|
||||
activeSection.value = detailData.task_info.service_provider === "zhongjian"
|
||||
? "zhongjian"
|
||||
: (detailData.supplement_task ? "supplement" : "result");
|
||||
|
||||
resultText.value = detailData.result_info.result_text || "";
|
||||
resultDesc.value = detailData.result_info.result_desc || "";
|
||||
if (hasConditionFields(detailData.appraisal_template)) {
|
||||
conditionGrade.value = detailData.result_info.condition_grade || "";
|
||||
conditionDesc.value = detailData.result_info.condition_desc || "";
|
||||
} else {
|
||||
conditionGrade.value = "";
|
||||
conditionDesc.value = "";
|
||||
}
|
||||
if (hasValuationFields(detailData.appraisal_template)) {
|
||||
valuationMin.value = detailData.result_info.valuation_min ? String(detailData.result_info.valuation_min) : "";
|
||||
valuationMax.value = detailData.result_info.valuation_max ? String(detailData.result_info.valuation_max) : "";
|
||||
valuationDesc.value = detailData.result_info.valuation_desc || "";
|
||||
} else {
|
||||
valuationMin.value = "";
|
||||
valuationMax.value = "";
|
||||
valuationDesc.value = "";
|
||||
}
|
||||
externalRemark.value = detailData.result_info.external_remark || "";
|
||||
internalRemark.value = detailData.result_info.internal_remark || "";
|
||||
zhongjianReportNo.value = detailData.zhongjian_report?.report_no || "";
|
||||
zhongjianFiles.value = [...(detailData.zhongjian_report?.files || [])];
|
||||
evidenceFiles.value = [...(detailData.result_info.attachments || [])];
|
||||
|
||||
if (detailData.supplement_task) {
|
||||
supplementForm.reason = detailData.supplement_task.reason || "";
|
||||
supplementForm.deadline = detailData.supplement_task.deadline || "";
|
||||
supplementForm.items.splice(
|
||||
0,
|
||||
supplementForm.items.length,
|
||||
...(detailData.supplement_task.items.length
|
||||
? detailData.supplement_task.items.map((item) => ({
|
||||
item_name: item.item_name,
|
||||
guide_text: item.guide_text,
|
||||
is_required: item.is_required,
|
||||
}))
|
||||
: [{ item_name: "", guide_text: "", is_required: true }]),
|
||||
);
|
||||
} else {
|
||||
supplementForm.reason = "";
|
||||
supplementForm.deadline = "";
|
||||
supplementForm.items.splice(0, supplementForm.items.length, {
|
||||
item_name: "",
|
||||
guide_text: "",
|
||||
is_required: true,
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
async function fetchDetail() {
|
||||
if (!taskId.value) return;
|
||||
loading.value = true;
|
||||
if (!pageReady.value) {
|
||||
loadError.value = "";
|
||||
}
|
||||
try {
|
||||
const data = await adminApi.getAppraisalTaskDetail(taskId.value);
|
||||
hydrate(data);
|
||||
pageReady.value = true;
|
||||
} catch (error) {
|
||||
if (!pageReady.value) {
|
||||
loadError.value = "工单详情加载失败,请稍后重试。";
|
||||
}
|
||||
showErrorToast(error, "工单详情加载失败");
|
||||
} finally {
|
||||
loading.value = false;
|
||||
}
|
||||
}
|
||||
|
||||
function addSupplementItem() {
|
||||
supplementForm.items.push({ item_name: "", guide_text: "", is_required: true });
|
||||
}
|
||||
|
||||
function removeSupplementItem(index: number) {
|
||||
if (supplementForm.items.length === 1) {
|
||||
supplementForm.items[0].item_name = "";
|
||||
supplementForm.items[0].guide_text = "";
|
||||
supplementForm.items[0].is_required = true;
|
||||
return;
|
||||
}
|
||||
supplementForm.items.splice(index, 1);
|
||||
}
|
||||
|
||||
async function removeEvidenceFile(fileUrl: string) {
|
||||
try {
|
||||
await adminApi.deleteAppraisalEvidenceFile(fileUrl);
|
||||
evidenceFiles.value = evidenceFiles.value.filter((item) => item.file_url !== fileUrl);
|
||||
showInfoToast("附件已删除");
|
||||
} catch (error) {
|
||||
showErrorToast(error, "附件删除失败");
|
||||
}
|
||||
}
|
||||
|
||||
async function removeZhongjianFile(fileUrl: string) {
|
||||
try {
|
||||
await adminApi.deleteAppraisalEvidenceFile(fileUrl);
|
||||
zhongjianFiles.value = zhongjianFiles.value.filter((item) => item.file_url !== fileUrl);
|
||||
showInfoToast("文件已删除");
|
||||
} catch (error) {
|
||||
showErrorToast(error, "文件删除失败");
|
||||
}
|
||||
}
|
||||
|
||||
function updateTemplatePoint(index: number, key: "point_value" | "point_remark", value: string) {
|
||||
const template = detail.value?.appraisal_template;
|
||||
if (!template) return;
|
||||
const current = template.key_points[index];
|
||||
if (!current) return;
|
||||
current[key] = value;
|
||||
}
|
||||
|
||||
function updateTemplatePointFromInput(
|
||||
index: number,
|
||||
key: "point_value" | "point_remark",
|
||||
event: Event,
|
||||
) {
|
||||
const target = event.target as HTMLInputElement | HTMLTextAreaElement | null;
|
||||
updateTemplatePoint(index, key, target?.value || "");
|
||||
}
|
||||
|
||||
function templateKeyPointsPayload() {
|
||||
return detail.value?.appraisal_template?.key_points?.map((item) => ({
|
||||
point_code: item.point_code,
|
||||
point_name: item.point_name,
|
||||
point_value: item.point_value || "",
|
||||
point_remark: item.point_remark || "",
|
||||
})) || [];
|
||||
}
|
||||
|
||||
function returnToWorkOrders(message: string) {
|
||||
showInfoToast(message);
|
||||
setTimeout(() => {
|
||||
uni.switchTab({ url: "/pages/work-order/index" });
|
||||
}, 700);
|
||||
}
|
||||
|
||||
async function chooseEvidenceImage() {
|
||||
try {
|
||||
const result = await uni.chooseImage({
|
||||
count: 9,
|
||||
sizeType: ["compressed"],
|
||||
sourceType: ["album", "camera"],
|
||||
});
|
||||
if (!result.tempFilePaths?.length) return;
|
||||
uploading.value = true;
|
||||
for (const filePath of result.tempFilePaths) {
|
||||
const asset = await adminApi.uploadAppraisalEvidenceFile(filePath);
|
||||
evidenceFiles.value.push(asset);
|
||||
}
|
||||
showInfoToast("图片上传成功");
|
||||
} catch (error) {
|
||||
showErrorToast(error, "图片上传失败");
|
||||
} finally {
|
||||
uploading.value = false;
|
||||
}
|
||||
}
|
||||
|
||||
async function chooseEvidenceVideo() {
|
||||
try {
|
||||
const result = await uni.chooseVideo({
|
||||
sourceType: ["album", "camera"],
|
||||
});
|
||||
const filePath = result.tempFilePath;
|
||||
if (!filePath) return;
|
||||
uploading.value = true;
|
||||
const asset = await adminApi.uploadAppraisalEvidenceFile(filePath);
|
||||
evidenceFiles.value.push(asset);
|
||||
showInfoToast("视频上传成功");
|
||||
} catch (error) {
|
||||
showErrorToast(error, "视频上传失败");
|
||||
} finally {
|
||||
uploading.value = false;
|
||||
}
|
||||
}
|
||||
|
||||
async function chooseZhongjianImage() {
|
||||
try {
|
||||
const result = await uni.chooseImage({
|
||||
count: 9,
|
||||
sizeType: ["compressed"],
|
||||
sourceType: ["album", "camera"],
|
||||
});
|
||||
if (!result.tempFilePaths?.length) return;
|
||||
uploading.value = true;
|
||||
for (const filePath of result.tempFilePaths) {
|
||||
const asset = await adminApi.uploadAppraisalEvidenceFile(filePath);
|
||||
zhongjianFiles.value.push(asset);
|
||||
}
|
||||
showInfoToast("图片上传成功");
|
||||
} catch (error) {
|
||||
showErrorToast(error, "图片上传失败");
|
||||
} finally {
|
||||
uploading.value = false;
|
||||
}
|
||||
}
|
||||
|
||||
async function chooseZhongjianVideo() {
|
||||
try {
|
||||
const result = await uni.chooseVideo({
|
||||
sourceType: ["album", "camera"],
|
||||
});
|
||||
const filePath = result.tempFilePath;
|
||||
if (!filePath) return;
|
||||
uploading.value = true;
|
||||
const asset = await adminApi.uploadAppraisalEvidenceFile(filePath);
|
||||
zhongjianFiles.value.push(asset);
|
||||
showInfoToast("视频上传成功");
|
||||
} catch (error) {
|
||||
showErrorToast(error, "视频上传失败");
|
||||
} finally {
|
||||
uploading.value = false;
|
||||
}
|
||||
}
|
||||
|
||||
async function submitResult(action: "save" | "submit") {
|
||||
if (!detail.value) return;
|
||||
if (isZhongjian.value) {
|
||||
showInfoToast("中检订单请切换到中检报告区");
|
||||
activeSection.value = "zhongjian";
|
||||
return;
|
||||
}
|
||||
|
||||
if (action === "submit" && !resultText.value.trim()) {
|
||||
showInfoToast("请先填写鉴定结论");
|
||||
return;
|
||||
}
|
||||
|
||||
submitting.value = true;
|
||||
try {
|
||||
const conditionPayload = showConditionFields.value
|
||||
? {
|
||||
condition_grade: conditionGrade.value.trim(),
|
||||
condition_desc: conditionDesc.value.trim(),
|
||||
}
|
||||
: {
|
||||
condition_grade: "",
|
||||
condition_desc: "",
|
||||
};
|
||||
const valuationPayload = showValuationFields.value
|
||||
? {
|
||||
valuation_min: formatMoneyInput(valuationMin.value),
|
||||
valuation_max: formatMoneyInput(valuationMax.value),
|
||||
valuation_desc: valuationDesc.value.trim(),
|
||||
}
|
||||
: {
|
||||
valuation_min: 0,
|
||||
valuation_max: 0,
|
||||
valuation_desc: "",
|
||||
};
|
||||
|
||||
await withLoading(action === "submit" ? "正在提交鉴定" : "正在保存鉴定", () =>
|
||||
adminApi.saveAppraisalTaskResult({
|
||||
id: detail.value!.task_info.id,
|
||||
action,
|
||||
product_info: {
|
||||
category_id: detail.value!.product_info.category_id,
|
||||
product_name: detail.value!.product_info.product_name,
|
||||
category_name: detail.value!.product_info.category_name,
|
||||
brand_name: detail.value!.product_info.brand_name,
|
||||
color: detail.value!.product_info.color,
|
||||
size_spec: detail.value!.product_info.size_spec,
|
||||
serial_no: detail.value!.product_info.serial_no,
|
||||
},
|
||||
result_text: resultText.value.trim(),
|
||||
result_desc: resultDesc.value.trim(),
|
||||
...conditionPayload,
|
||||
...valuationPayload,
|
||||
external_remark: externalRemark.value.trim(),
|
||||
internal_remark: internalRemark.value.trim(),
|
||||
attachments: evidenceFiles.value,
|
||||
key_points: templateKeyPointsPayload(),
|
||||
}),
|
||||
);
|
||||
if (action === "submit") {
|
||||
returnToWorkOrders("鉴定已提交,正在返回工单");
|
||||
return;
|
||||
}
|
||||
showInfoToast("鉴定已保存");
|
||||
await fetchDetail();
|
||||
} catch (error) {
|
||||
showErrorToast(error, action === "submit" ? "鉴定提交失败" : "鉴定保存失败");
|
||||
} finally {
|
||||
submitting.value = false;
|
||||
}
|
||||
}
|
||||
|
||||
async function submitSupplement() {
|
||||
if (!detail.value) return;
|
||||
const items = supplementForm.items.filter((item) => item.item_name.trim());
|
||||
if (!supplementForm.reason.trim()) {
|
||||
showInfoToast("请先填写补资料原因");
|
||||
return;
|
||||
}
|
||||
if (!items.length) {
|
||||
showInfoToast("请至少填写一项补资料要求");
|
||||
return;
|
||||
}
|
||||
|
||||
supplementSubmitting.value = true;
|
||||
try {
|
||||
await adminApi.requestAppraisalTaskSupplement({
|
||||
id: detail.value.task_info.id,
|
||||
reason: supplementForm.reason.trim(),
|
||||
deadline: supplementForm.deadline.trim(),
|
||||
items: items.map((item) => ({
|
||||
item_name: item.item_name.trim(),
|
||||
guide_text: item.guide_text.trim(),
|
||||
is_required: item.is_required,
|
||||
})),
|
||||
});
|
||||
showInfoToast("已发起补资料要求");
|
||||
await fetchDetail();
|
||||
} catch (error) {
|
||||
showErrorToast(error, "发起补资料失败");
|
||||
} finally {
|
||||
supplementSubmitting.value = false;
|
||||
}
|
||||
}
|
||||
|
||||
async function submitZhongjianReport() {
|
||||
if (!detail.value) return;
|
||||
if (!zhongjianReportNo.value.trim()) {
|
||||
showInfoToast("请填写中检报告编号");
|
||||
return;
|
||||
}
|
||||
if (!zhongjianFiles.value.length) {
|
||||
showInfoToast("请至少上传 1 个中检报告文件");
|
||||
return;
|
||||
}
|
||||
|
||||
submitting.value = true;
|
||||
try {
|
||||
await adminApi.saveZhongjianAppraisalReport({
|
||||
id: detail.value.task_info.id,
|
||||
zhongjian_report_no: zhongjianReportNo.value.trim(),
|
||||
report_files: zhongjianFiles.value,
|
||||
});
|
||||
returnToWorkOrders("中检报告已提交,正在返回工单");
|
||||
} catch (error) {
|
||||
showErrorToast(error, "中检报告录入失败");
|
||||
} finally {
|
||||
submitting.value = false;
|
||||
}
|
||||
}
|
||||
|
||||
function openReportDetail() {
|
||||
const reportId = Number(detail.value?.report_summary?.id || 0);
|
||||
if (!reportId) return;
|
||||
uni.navigateTo({ url: `/pages/report/detail?id=${reportId}` });
|
||||
}
|
||||
|
||||
onLoad((options) => {
|
||||
taskId.value = Number(options?.id || 0);
|
||||
if (!taskId.value) {
|
||||
loadError.value = "缺少工单编号,无法查看详情。";
|
||||
}
|
||||
});
|
||||
|
||||
onShow(() => {
|
||||
if (taskId.value) {
|
||||
void fetchDetail();
|
||||
}
|
||||
});
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<view class="page">
|
||||
<view v-if="!pageReady && loading" class="empty">正在加载工单详情</view>
|
||||
<view v-else-if="!pageReady && loadError" class="empty">{{ loadError }}</view>
|
||||
|
||||
<template v-else-if="detail">
|
||||
<view class="hero">
|
||||
<view class="eyebrow">鉴定工单</view>
|
||||
<view class="title">{{ detail.product_info.product_name || "待完善物品信息" }}</view>
|
||||
<view class="subtitle">{{ detail.task_info.order_no }} / {{ detail.task_info.appraisal_no }}</view>
|
||||
</view>
|
||||
|
||||
<view class="card">
|
||||
<view class="row">
|
||||
<view>
|
||||
<view class="card-title">{{ detail.task_info.task_stage_text }} · {{ detail.task_info.status_text }}</view>
|
||||
<view class="card-desc">{{ detail.task_info.service_provider_text }} / {{ detail.task_info.assignee_name }}</view>
|
||||
</view>
|
||||
<text class="tag">{{ resultSummary }}</text>
|
||||
</view>
|
||||
<view class="meta-grid">
|
||||
<view class="meta-item">
|
||||
<view class="meta-label">SLA 截止</view>
|
||||
<view class="meta-value">{{ detail.task_info.sla_deadline || "-" }}</view>
|
||||
</view>
|
||||
<view class="meta-item">
|
||||
<view class="meta-label">开始时间</view>
|
||||
<view class="meta-value">{{ detail.task_info.started_at || "-" }}</view>
|
||||
</view>
|
||||
<view class="meta-item">
|
||||
<view class="meta-label">提交时间</view>
|
||||
<view class="meta-value">{{ detail.task_info.submitted_at || "-" }}</view>
|
||||
</view>
|
||||
<view class="meta-item">
|
||||
<view class="meta-label">报告摘要</view>
|
||||
<view class="meta-value">{{ reportSummary || "-" }}</view>
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
|
||||
<view class="card">
|
||||
<view class="segmented">
|
||||
<view :class="['segment', activeSection === 'result' ? 'segment--active' : '']" @click="activeSection = 'result'">鉴定结论</view>
|
||||
<view :class="['segment', activeSection === 'supplement' ? 'segment--active' : '']" @click="activeSection = 'supplement'">补资料</view>
|
||||
<view :class="['segment', activeSection === 'zhongjian' ? 'segment--active' : '']" @click="activeSection = 'zhongjian'">中检报告</view>
|
||||
</view>
|
||||
</view>
|
||||
|
||||
<view v-if="activeSection === 'result' && !isZhongjian" class="card">
|
||||
<view class="card-title">鉴定结论</view>
|
||||
<view class="stack" style="margin-top: 18rpx">
|
||||
<input v-model="resultText" class="field" placeholder="结论,例如:正品 / 存疑" />
|
||||
<textarea v-model="resultDesc" class="textarea" placeholder="结论说明" />
|
||||
<template v-if="showConditionFields">
|
||||
<input v-model="conditionGrade" class="field" placeholder="成色评级" />
|
||||
<textarea v-model="conditionDesc" class="textarea" placeholder="成色说明" />
|
||||
</template>
|
||||
<template v-if="showValuationFields">
|
||||
<view class="meta-grid">
|
||||
<input v-model="valuationMin" class="field" placeholder="最低估值" />
|
||||
<input v-model="valuationMax" class="field" placeholder="最高估值" />
|
||||
</view>
|
||||
<textarea v-model="valuationDesc" class="textarea" placeholder="估值说明" />
|
||||
</template>
|
||||
<textarea v-model="externalRemark" class="textarea" placeholder="对外备注" />
|
||||
<textarea v-model="internalRemark" class="textarea" placeholder="内部备注" />
|
||||
</view>
|
||||
|
||||
<view v-if="detail.appraisal_template?.key_points?.length" class="stack" style="margin-top: 20rpx">
|
||||
<view class="card-desc">模板项</view>
|
||||
<view v-for="(item, index) in detail.appraisal_template.key_points" :key="item.point_code" class="stack">
|
||||
<view class="meta-item">
|
||||
<view class="meta-label">{{ item.point_name }}</view>
|
||||
<view class="meta-value">{{ item.point_type }}{{ item.is_required ? " · 必填" : "" }}</view>
|
||||
</view>
|
||||
<input
|
||||
:value="item.point_value"
|
||||
class="field"
|
||||
:placeholder="`${item.point_name} 值`"
|
||||
@input="updateTemplatePointFromInput(index, 'point_value', $event)"
|
||||
/>
|
||||
<textarea
|
||||
:value="item.point_remark"
|
||||
class="textarea"
|
||||
:placeholder="`${item.point_name} 说明`"
|
||||
@input="updateTemplatePointFromInput(index, 'point_remark', $event)"
|
||||
/>
|
||||
</view>
|
||||
</view>
|
||||
|
||||
<view class="card-desc evidence-title">证据附件</view>
|
||||
<view v-if="evidenceFiles.length" class="list" style="margin-top: 14rpx">
|
||||
<view v-for="item in evidenceFiles" :key="item.file_url" class="list-card">
|
||||
<view class="row">
|
||||
<view class="list-title">{{ item.name || item.file_id }}</view>
|
||||
<text class="tag tag--danger" @click="removeEvidenceFile(item.file_url)">删除</text>
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
<view class="upload-actions">
|
||||
<button class="action-button action-button--secondary" :disabled="uploading" @click="chooseEvidenceImage">
|
||||
<text class="action-symbol">+</text>
|
||||
<text>{{ uploading ? "上传中" : "添加图片" }}</text>
|
||||
</button>
|
||||
<button class="action-button action-button--secondary" :disabled="uploading" @click="chooseEvidenceVideo">
|
||||
<text class="action-symbol">+</text>
|
||||
<text>{{ uploading ? "上传中" : "添加视频" }}</text>
|
||||
</button>
|
||||
</view>
|
||||
|
||||
<view class="form-actions">
|
||||
<button class="form-action form-action--secondary" :disabled="submitting" @click="submitResult('save')">保存</button>
|
||||
<button class="form-action form-action--primary" :disabled="submitting" @click="submitResult('submit')">提交</button>
|
||||
</view>
|
||||
</view>
|
||||
|
||||
<view v-else-if="activeSection === 'supplement'" class="card">
|
||||
<view class="card-title">补资料</view>
|
||||
<view class="stack" style="margin-top: 18rpx">
|
||||
<textarea v-model="supplementForm.reason" class="textarea" placeholder="补资料原因" />
|
||||
<input v-model="supplementForm.deadline" class="field" placeholder="截止时间(可选)" />
|
||||
<view v-for="(item, index) in supplementForm.items" :key="index" class="stack">
|
||||
<input v-model="item.item_name" class="field" placeholder="补资料项名称" />
|
||||
<textarea v-model="item.guide_text" class="textarea" placeholder="补资料说明" />
|
||||
<view class="row">
|
||||
<text class="tag" :class="item.is_required ? 'tag--warning' : ''" @click="item.is_required = !item.is_required">
|
||||
{{ item.is_required ? "必传" : "选传" }}
|
||||
</text>
|
||||
<text class="tag tag--danger" @click="removeSupplementItem(index)">删除</text>
|
||||
</view>
|
||||
</view>
|
||||
<view class="form-actions">
|
||||
<button class="form-action form-action--secondary" @click="addSupplementItem">添加一项</button>
|
||||
<button class="form-action form-action--primary" :disabled="supplementSubmitting" @click="submitSupplement">发起补资料</button>
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
|
||||
<view v-else class="card">
|
||||
<view class="card-title">中检报告</view>
|
||||
<view class="stack" style="margin-top: 18rpx">
|
||||
<input v-model="zhongjianReportNo" class="field" placeholder="中检报告编号" />
|
||||
<view v-if="zhongjianFiles.length" class="list">
|
||||
<view v-for="item in zhongjianFiles" :key="item.file_url" class="list-card">
|
||||
<view class="row">
|
||||
<view class="list-title">{{ item.name || item.file_id }}</view>
|
||||
<text class="tag tag--danger" @click="removeZhongjianFile(item.file_url)">删除</text>
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
<view class="upload-actions">
|
||||
<button class="action-button action-button--secondary" :disabled="uploading" @click="chooseZhongjianImage">
|
||||
<text class="action-symbol">+</text>
|
||||
<text>{{ uploading ? "上传中" : "添加图片" }}</text>
|
||||
</button>
|
||||
<button class="action-button action-button--secondary" :disabled="uploading" @click="chooseZhongjianVideo">
|
||||
<text class="action-symbol">+</text>
|
||||
<text>{{ uploading ? "上传中" : "添加视频" }}</text>
|
||||
</button>
|
||||
</view>
|
||||
<view class="form-actions" :class="detail.report_summary?.id ? '' : 'form-actions--single'">
|
||||
<button class="form-action form-action--primary" :disabled="submitting" @click="submitZhongjianReport">提交并发布</button>
|
||||
<button v-if="detail.report_summary?.id" class="form-action form-action--secondary" @click="openReportDetail">查看报告</button>
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
|
||||
<view class="card">
|
||||
<view class="card-title">任务信息</view>
|
||||
<view class="meta-grid">
|
||||
<view class="meta-item">
|
||||
<view class="meta-label">订单号</view>
|
||||
<view class="meta-value">{{ detail.task_info.order_no }}</view>
|
||||
</view>
|
||||
<view class="meta-item">
|
||||
<view class="meta-label">鉴定单号</view>
|
||||
<view class="meta-value">{{ detail.task_info.appraisal_no }}</view>
|
||||
</view>
|
||||
<view class="meta-item">
|
||||
<view class="meta-label">服务类型</view>
|
||||
<view class="meta-value">{{ detail.task_info.service_provider_text }}</view>
|
||||
</view>
|
||||
<view class="meta-item">
|
||||
<view class="meta-label">处理人</view>
|
||||
<view class="meta-value">{{ detail.task_info.assignee_name }}</view>
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
</template>
|
||||
</view>
|
||||
</template>
|
||||
|
||||
<style scoped lang="scss">
|
||||
.list {
|
||||
display: grid;
|
||||
gap: 14rpx;
|
||||
}
|
||||
|
||||
.evidence-title {
|
||||
margin-top: 24rpx;
|
||||
color: var(--work-text);
|
||||
font-weight: 800;
|
||||
}
|
||||
|
||||
.upload-actions {
|
||||
display: grid;
|
||||
grid-template-columns: repeat(2, minmax(0, 1fr));
|
||||
gap: 16rpx;
|
||||
margin-top: 16rpx;
|
||||
}
|
||||
|
||||
.action-button,
|
||||
.form-action {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
min-width: 0;
|
||||
min-height: 88rpx;
|
||||
padding: 0 22rpx;
|
||||
border: 1px solid transparent;
|
||||
border-radius: var(--work-radius-sm);
|
||||
font-size: 28rpx;
|
||||
font-weight: 800;
|
||||
line-height: 1;
|
||||
}
|
||||
|
||||
.action-button::after,
|
||||
.form-action::after {
|
||||
border: 0;
|
||||
}
|
||||
|
||||
.action-button[disabled],
|
||||
.form-action[disabled] {
|
||||
opacity: 0.56;
|
||||
}
|
||||
|
||||
.action-button--secondary {
|
||||
justify-content: flex-start;
|
||||
gap: 12rpx;
|
||||
border-color: var(--work-border);
|
||||
background: var(--work-card-muted);
|
||||
color: var(--work-text);
|
||||
}
|
||||
|
||||
.action-symbol {
|
||||
width: 36rpx;
|
||||
height: 36rpx;
|
||||
border-radius: 50%;
|
||||
background: #ffffff;
|
||||
color: var(--work-accent-deep);
|
||||
font-size: 30rpx;
|
||||
font-weight: 800;
|
||||
line-height: 34rpx;
|
||||
text-align: center;
|
||||
}
|
||||
|
||||
.form-actions {
|
||||
display: grid;
|
||||
grid-template-columns: minmax(0, 1fr) minmax(0, 1.25fr);
|
||||
gap: 16rpx;
|
||||
margin-top: 24rpx;
|
||||
}
|
||||
|
||||
.form-actions--single {
|
||||
grid-template-columns: 1fr;
|
||||
}
|
||||
|
||||
.form-action--secondary {
|
||||
border-color: var(--work-border);
|
||||
background: #ffffff;
|
||||
color: var(--work-text);
|
||||
}
|
||||
|
||||
.form-action--primary {
|
||||
border-color: var(--work-accent);
|
||||
background: var(--work-accent);
|
||||
color: #ffffff;
|
||||
}
|
||||
</style>
|
||||
Reference in New Issue
Block a user