feat: align work app report detail style
This commit is contained in:
@@ -2,8 +2,8 @@
|
||||
"name": "安心验作业端",
|
||||
"appid": "__UNI__E0C8390",
|
||||
"description": "安心验仓管与鉴定作业 Android App",
|
||||
"versionName": "1.0.1",
|
||||
"versionCode": "102",
|
||||
"versionName": "1.0.2",
|
||||
"versionCode": "103",
|
||||
"transformPx": false,
|
||||
"app-plus": {
|
||||
"usingComponents": true,
|
||||
|
||||
@@ -4,6 +4,8 @@ import { onLoad, onShow } from "@dcloudio/uni-app";
|
||||
import { adminApi, type AdminFileAsset, type AdminReportDetail } from "../../api/admin";
|
||||
import { showErrorToast, showInfoToast } from "../../utils/feedback";
|
||||
|
||||
type ReportTab = "product" | "attachments";
|
||||
|
||||
const loading = ref(false);
|
||||
const pageReady = ref(false);
|
||||
const loadError = ref("");
|
||||
@@ -11,74 +13,83 @@ const detail = ref<AdminReportDetail | null>(null);
|
||||
const reportId = ref(0);
|
||||
const returnInternalTagNo = ref("");
|
||||
const returnConfirming = ref(false);
|
||||
const activeTab = ref<ReportTab>("product");
|
||||
const activeVideo = ref<AdminFileAsset | null>(null);
|
||||
|
||||
const isZhongjian = computed(() => detail.value?.report_header.service_provider === "zhongjian");
|
||||
const isReturnReview = computed(() => Boolean(returnInternalTagNo.value && reportId.value));
|
||||
const reportMetaItems = computed(() => {
|
||||
const current = detail.value;
|
||||
if (!current) return [];
|
||||
|
||||
const items = [
|
||||
{ label: "发布时间", value: current.report_header.publish_time || "-" },
|
||||
];
|
||||
const appraiserName = textValue(current.appraisal_info?.appraiser_name)
|
||||
|| textValue(current.report_header.report_entry_admin_name);
|
||||
if (appraiserName) {
|
||||
items.push({ label: "鉴定师", value: appraiserName });
|
||||
}
|
||||
if (isZhongjian.value) {
|
||||
items.push({ label: "中检报告号", value: current.report_header.zhongjian_report_no || "-" });
|
||||
items.push({ label: "报告录入人", value: current.report_header.report_entry_admin_name || "-" });
|
||||
}
|
||||
|
||||
return items;
|
||||
});
|
||||
const resultMetaItems = computed(() => {
|
||||
const current = detail.value;
|
||||
if (!current) return [];
|
||||
|
||||
const result = current.result_info || {};
|
||||
const valuation = current.valuation_info || {};
|
||||
const items = [
|
||||
{ label: "结论", value: textValue(result.result_text) || "-" },
|
||||
{ label: "结论说明", value: textValue(result.result_desc) || "-" },
|
||||
];
|
||||
|
||||
for (const point of normalizedKeyPoints(result.key_points)) {
|
||||
items.push({
|
||||
label: point.point_name,
|
||||
value: point.point_value || "-",
|
||||
});
|
||||
}
|
||||
|
||||
const conditionGrade = textValue(valuation.condition_grade);
|
||||
const conditionDesc = textValue(valuation.condition_desc);
|
||||
if (conditionGrade || conditionDesc) {
|
||||
items.push({ label: "成色评级", value: [conditionGrade, conditionDesc].filter(Boolean).join(";") || "-" });
|
||||
}
|
||||
|
||||
const valuationMin = Number(valuation.valuation_min || 0);
|
||||
const valuationMax = Number(valuation.valuation_max || 0);
|
||||
const valuationDesc = textValue(valuation.valuation_desc);
|
||||
if (valuationMin > 0 || valuationMax > 0 || valuationDesc) {
|
||||
const range = valuationMin > 0 || valuationMax > 0 ? `¥${valuationMin} - ¥${valuationMax}` : "";
|
||||
items.push({ label: "估值", value: [range, valuationDesc].filter(Boolean).join(";") || "-" });
|
||||
}
|
||||
|
||||
const externalRemark = textValue(result.external_remark);
|
||||
if (externalRemark) {
|
||||
items.push({ label: "备注", value: externalRemark });
|
||||
}
|
||||
|
||||
return items;
|
||||
});
|
||||
const evidenceAttachments = computed(() => detail.value?.evidence_attachments || []);
|
||||
const zhongjianReportFiles = computed(() => isZhongjian.value ? (detail.value?.zhongjian_report_files || []) : []);
|
||||
const imageEvidenceList = computed(() => evidenceAttachments.value.filter(isImageAsset));
|
||||
const fileEvidenceList = computed(() => evidenceAttachments.value.filter((item) => !isImageAsset(item)));
|
||||
const zhongjianImageFiles = computed(() => zhongjianReportFiles.value.filter(isImageAsset));
|
||||
const zhongjianOtherFiles = computed(() => zhongjianReportFiles.value.filter((item) => !isImageAsset(item)));
|
||||
const reportImages = computed(() => {
|
||||
if (imageEvidenceList.value.length) return imageEvidenceList.value;
|
||||
return zhongjianImageFiles.value;
|
||||
});
|
||||
const hasAttachments = computed(() => evidenceAttachments.value.length > 0 || zhongjianReportFiles.value.length > 0);
|
||||
const reportNo = computed(() => textValue(detail.value?.report_header.report_no) || "-");
|
||||
const productName = computed(() => textValue(detail.value?.product_info?.product_name) || "-");
|
||||
const institutionName = computed(() => textValue(detail.value?.report_header.institution_name) || "-");
|
||||
const publishTime = computed(() => textValue(detail.value?.report_header.publish_time) || "-");
|
||||
const resultItem = computed(() => {
|
||||
const result = detail.value?.result_info || {};
|
||||
return {
|
||||
label: "检测结论",
|
||||
value: textValue(result.result_text) || "-",
|
||||
remark: textValue(result.result_desc),
|
||||
};
|
||||
});
|
||||
const productSpecItems = computed(() => {
|
||||
const current = detail.value;
|
||||
if (!current) return [];
|
||||
|
||||
function previewImage(urls: string[], current: string) {
|
||||
if (!urls.length) return;
|
||||
uni.previewImage({ urls, current });
|
||||
const product = current.product_info || {};
|
||||
const result = current.result_info || {};
|
||||
const valuation = current.valuation_info || {};
|
||||
const items: Array<{ label: string; value: string; remark?: string }> = [];
|
||||
|
||||
appendSpecItem(items, "品类", product.category_name);
|
||||
appendSpecItem(items, "品牌", product.brand_name);
|
||||
appendSpecItem(items, "颜色", product.color);
|
||||
appendSpecItem(items, "规格/尺寸", product.size_spec);
|
||||
appendSpecItem(items, "序列号/编码", product.serial_no);
|
||||
|
||||
for (const point of normalizedKeyPoints(result.key_points)) {
|
||||
appendSpecItem(items, point.point_name, point.point_value, point.point_remark);
|
||||
}
|
||||
|
||||
appendSpecItem(items, "服务类型", current.report_header.service_provider_text);
|
||||
if (isZhongjian.value) {
|
||||
appendSpecItem(items, "中检报告号", current.report_header.zhongjian_report_no);
|
||||
appendSpecItem(items, "报告录入人", current.report_header.report_entry_admin_name);
|
||||
}
|
||||
|
||||
const appraiserName = textValue(current.appraisal_info?.appraiser_name)
|
||||
|| textValue(current.report_header.report_entry_admin_name);
|
||||
appendSpecItem(items, "鉴定师", appraiserName);
|
||||
appendSpecItem(items, "成色评级", valuation.condition_grade, valuation.condition_desc);
|
||||
appendSpecItem(items, "估值区间", formatValuationRange(valuation.valuation_min, valuation.valuation_max), valuation.valuation_desc);
|
||||
appendSpecItem(items, "备注", result.external_remark);
|
||||
|
||||
return items;
|
||||
});
|
||||
|
||||
function appendSpecItem(
|
||||
items: Array<{ label: string; value: string; remark?: string }>,
|
||||
label: string,
|
||||
value: unknown,
|
||||
remark: unknown = "",
|
||||
) {
|
||||
const valueText = textValue(value);
|
||||
const remarkText = textValue(remark);
|
||||
if (!valueText && !remarkText) return;
|
||||
items.push({
|
||||
label,
|
||||
value: valueText || "-",
|
||||
remark: remarkText,
|
||||
});
|
||||
}
|
||||
|
||||
function textValue(value: unknown) {
|
||||
@@ -97,7 +108,25 @@ function normalizedKeyPoints(value: unknown) {
|
||||
point_remark: textValue(point.point_remark),
|
||||
};
|
||||
})
|
||||
.filter((item) => item.point_value);
|
||||
.filter((item) => item.point_value || item.point_remark);
|
||||
}
|
||||
|
||||
function formatValuationRange(min: unknown, max: unknown) {
|
||||
const minValue = Number(min || 0);
|
||||
const maxValue = Number(max || 0);
|
||||
if (minValue <= 0 && maxValue <= 0) return "";
|
||||
if (minValue > 0 && maxValue > 0) return `¥${formatMoney(minValue)} - ¥${formatMoney(maxValue)}`;
|
||||
if (minValue > 0) return `¥${formatMoney(minValue)} 起`;
|
||||
return `¥${formatMoney(maxValue)} 内`;
|
||||
}
|
||||
|
||||
function formatMoney(value: number) {
|
||||
return String(Number(value.toFixed(2))).replace(/\.0+$/, "");
|
||||
}
|
||||
|
||||
function previewImage(urls: string[], current: string) {
|
||||
if (!urls.length) return;
|
||||
uni.previewImage({ urls, current });
|
||||
}
|
||||
|
||||
function isImageAsset(item: AdminFileAsset) {
|
||||
@@ -115,13 +144,13 @@ function assetTypeLabel(item: AdminFileAsset) {
|
||||
return "附件";
|
||||
}
|
||||
|
||||
function openAsset(item: AdminFileAsset) {
|
||||
function assetDisplayName(item: AdminFileAsset, index: number) {
|
||||
return item.name || `${assetTypeLabel(item)} ${index + 1}`;
|
||||
}
|
||||
|
||||
function openAsset(item: AdminFileAsset, files: AdminFileAsset[]) {
|
||||
if (isImageAsset(item)) {
|
||||
const urls = [
|
||||
...evidenceAttachments.value.filter(isImageAsset).map((asset) => asset.file_url),
|
||||
...zhongjianReportFiles.value.filter(isImageAsset).map((asset) => asset.file_url),
|
||||
];
|
||||
previewImage(urls, item.file_url);
|
||||
previewImage(files.filter(isImageAsset).map((asset) => asset.file_url), item.file_url);
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -227,112 +256,152 @@ onShow(() => {
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<view class="page">
|
||||
<view v-if="!pageReady && loading" class="empty">正在加载报告详情</view>
|
||||
<view v-else-if="!pageReady && loadError" class="empty">{{ loadError }}</view>
|
||||
<view :class="['page', 'report-page', isReturnReview ? 'report-page--with-action' : '']">
|
||||
<view v-if="!pageReady && loading" class="notice-card">
|
||||
<view class="notice-card__title">正在加载报告详情</view>
|
||||
<view class="notice-card__desc">请稍候,正在同步报告正文与附件。</view>
|
||||
</view>
|
||||
<view v-else-if="!pageReady && loadError" class="notice-card">
|
||||
<view class="notice-card__title">报告详情加载失败</view>
|
||||
<view class="notice-card__desc">{{ loadError }}</view>
|
||||
</view>
|
||||
|
||||
<template v-else-if="detail">
|
||||
<view class="hero">
|
||||
<view class="eyebrow">报告详情</view>
|
||||
<view class="title">{{ detail.report_header.report_title }}</view>
|
||||
<view class="subtitle">{{ detail.report_header.report_no }}</view>
|
||||
<view v-if="isReturnReview" class="review-strip">
|
||||
<view>
|
||||
<view class="review-strip__title">回寄前报告核对</view>
|
||||
<view class="review-strip__desc">核对报告编号、结论和附件后进入回寄登记。</view>
|
||||
</view>
|
||||
<text class="review-strip__tag">待确认</text>
|
||||
</view>
|
||||
|
||||
<view v-if="isReturnReview" class="card return-review-card">
|
||||
<view class="card-title">回寄前报告核对</view>
|
||||
<view class="card-desc">请核对报告编号、结论和附件,确认无误后进入回寄信息填写。</view>
|
||||
<button class="btn btn--primary main-action" :disabled="returnConfirming" @click="confirmReturnFromReport">
|
||||
<view class="report-shell">
|
||||
<view class="report-cover">
|
||||
<swiper v-if="reportImages.length" class="report-cover__swiper" indicator-dots circular>
|
||||
<swiper-item v-for="item in reportImages" :key="item.file_url || item.file_id">
|
||||
<image
|
||||
class="report-cover__image"
|
||||
:src="item.thumbnail_url || item.file_url"
|
||||
mode="aspectFill"
|
||||
@click="openAsset(item, reportImages)"
|
||||
/>
|
||||
</swiper-item>
|
||||
</swiper>
|
||||
<view v-else class="report-cover__empty">暂无鉴定图片</view>
|
||||
</view>
|
||||
|
||||
<view class="report-meta">
|
||||
<view class="report-meta__row">
|
||||
<text class="report-meta__label">产品名称</text>
|
||||
<text class="report-meta__value">{{ productName }}</text>
|
||||
</view>
|
||||
<view class="report-meta__row">
|
||||
<text class="report-meta__label">检测机构</text>
|
||||
<text class="report-meta__value">{{ institutionName }}</text>
|
||||
</view>
|
||||
<view class="report-meta__row">
|
||||
<text class="report-meta__label">报告编号</text>
|
||||
<text class="report-meta__value">{{ reportNo }}</text>
|
||||
</view>
|
||||
<view class="report-meta__row report-meta__row--date">
|
||||
<text class="report-meta__label">出具日期</text>
|
||||
<text class="report-meta__tag">{{ detail.report_header.report_status_text }}</text>
|
||||
<text class="report-meta__value">{{ publishTime }}</text>
|
||||
</view>
|
||||
</view>
|
||||
|
||||
<view class="report-tabs">
|
||||
<view :class="['report-tab', activeTab === 'product' ? 'report-tab--active' : '']" @click="activeTab = 'product'">产品信息</view>
|
||||
<view :class="['report-tab', activeTab === 'attachments' ? 'report-tab--active' : '']" @click="activeTab = 'attachments'">核验附件</view>
|
||||
</view>
|
||||
|
||||
<view v-if="activeTab === 'product'" class="report-panel">
|
||||
<view class="report-watermark" aria-hidden="true"></view>
|
||||
|
||||
<view class="report-result">
|
||||
<view class="report-result__content">
|
||||
<view class="report-result__label">{{ resultItem.label }}</view>
|
||||
<view class="report-result__value">{{ resultItem.value }}</view>
|
||||
<view v-if="resultItem.remark" class="report-result__desc">{{ resultItem.remark }}</view>
|
||||
</view>
|
||||
<view class="report-seal">
|
||||
<text class="report-seal__brand">ANXINYAN</text>
|
||||
<text class="report-seal__main">可信</text>
|
||||
</view>
|
||||
</view>
|
||||
|
||||
<view class="product-spec">
|
||||
<view v-for="(item, index) in productSpecItems" :key="`${item.label}-${index}`" class="product-spec__row">
|
||||
<view class="product-spec__label">{{ item.label }}</view>
|
||||
<view class="product-spec__line"></view>
|
||||
<view class="product-spec__value">{{ item.value || "-" }}</view>
|
||||
<view v-if="item.remark" class="product-spec__remark">{{ item.remark }}</view>
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
|
||||
<view v-else class="report-panel report-panel--attachments">
|
||||
<view v-if="!hasAttachments" class="attachment-empty">暂无核验附件</view>
|
||||
|
||||
<view v-if="evidenceAttachments.length" class="inline-section">
|
||||
<view class="inline-section__title">鉴定证据</view>
|
||||
<view v-if="imageEvidenceList.length" class="asset-grid">
|
||||
<view
|
||||
v-for="item in imageEvidenceList"
|
||||
:key="item.file_url || item.file_id"
|
||||
class="asset-tile"
|
||||
@click="openAsset(item, imageEvidenceList)"
|
||||
>
|
||||
<image class="asset-tile__image" :src="item.thumbnail_url || item.file_url" mode="aspectFill" />
|
||||
</view>
|
||||
</view>
|
||||
<view v-if="fileEvidenceList.length" class="asset-list">
|
||||
<view
|
||||
v-for="(item, index) in fileEvidenceList"
|
||||
:key="item.file_url || item.file_id"
|
||||
class="asset-list__item"
|
||||
@click="openAsset(item, fileEvidenceList)"
|
||||
>
|
||||
<text>{{ assetDisplayName(item, index) }}</text>
|
||||
<text class="asset-list__type">{{ assetTypeLabel(item) }}</text>
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
|
||||
<view v-if="isZhongjian || zhongjianReportFiles.length" class="inline-section">
|
||||
<view class="inline-section__title">中检报告文件</view>
|
||||
<view v-if="zhongjianImageFiles.length" class="asset-grid">
|
||||
<view
|
||||
v-for="item in zhongjianImageFiles"
|
||||
:key="item.file_url || item.file_id"
|
||||
class="asset-tile"
|
||||
@click="openAsset(item, zhongjianImageFiles)"
|
||||
>
|
||||
<image class="asset-tile__image" :src="item.thumbnail_url || item.file_url" mode="aspectFill" />
|
||||
</view>
|
||||
</view>
|
||||
<view v-if="zhongjianOtherFiles.length" class="asset-list">
|
||||
<view
|
||||
v-for="(item, index) in zhongjianOtherFiles"
|
||||
:key="item.file_url || item.file_id"
|
||||
class="asset-list__item"
|
||||
@click="openAsset(item, zhongjianOtherFiles)"
|
||||
>
|
||||
<text>{{ assetDisplayName(item, index) }}</text>
|
||||
<text class="asset-list__type">{{ assetTypeLabel(item) }}</text>
|
||||
</view>
|
||||
</view>
|
||||
<view v-if="isZhongjian && !zhongjianReportFiles.length" class="attachment-empty attachment-empty--compact">暂无中检报告文件</view>
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
|
||||
<view v-if="isReturnReview" class="report-actions">
|
||||
<button class="report-actions__button" :disabled="returnConfirming" @click="confirmReturnFromReport">
|
||||
{{ returnConfirming ? "确认中" : "确认寄回" }}
|
||||
</button>
|
||||
</view>
|
||||
|
||||
<view class="card">
|
||||
<view class="row">
|
||||
<view>
|
||||
<view class="card-title">{{ detail.report_header.report_status_text }}</view>
|
||||
<view class="card-desc">{{ detail.report_header.institution_name }}</view>
|
||||
</view>
|
||||
<text class="tag">{{ detail.report_header.service_provider_text }}</text>
|
||||
</view>
|
||||
<view class="meta-grid">
|
||||
<view v-for="item in reportMetaItems" :key="item.label" class="meta-item">
|
||||
<view class="meta-label">{{ item.label }}</view>
|
||||
<view class="meta-value">{{ item.value }}</view>
|
||||
</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.product_info.product_name || "-" }}</view>
|
||||
</view>
|
||||
<view class="meta-item">
|
||||
<view class="meta-label">品类 / 品牌</view>
|
||||
<view class="meta-value">{{ detail.product_info.category_name || "-" }} / {{ detail.product_info.brand_name || "-" }}</view>
|
||||
</view>
|
||||
<view class="meta-item">
|
||||
<view class="meta-label">颜色 / 规格</view>
|
||||
<view class="meta-value">{{ detail.product_info.color || "-" }} / {{ detail.product_info.size_spec || "-" }}</view>
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
|
||||
<view class="card">
|
||||
<view class="card-title">鉴定结果</view>
|
||||
<view class="meta-grid">
|
||||
<view v-for="(item, index) in resultMetaItems" :key="`${item.label}-${index}`" class="meta-item">
|
||||
<view class="meta-label">{{ item.label }}</view>
|
||||
<view class="meta-value">{{ item.value }}</view>
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
|
||||
<view class="card">
|
||||
<view class="card-title">附件</view>
|
||||
<view v-if="evidenceAttachments.length" class="attachment-grid">
|
||||
<view v-for="item in evidenceAttachments" :key="item.file_url || item.file_id" class="attachment-tile">
|
||||
<view class="attachment-preview" @click="openAsset(item)">
|
||||
<image v-if="isImageAsset(item)" class="attachment-thumb" :src="item.thumbnail_url || item.file_url" mode="aspectFill" />
|
||||
<template v-else-if="isVideoAsset(item)">
|
||||
<image v-if="item.thumbnail_url" class="attachment-thumb" :src="item.thumbnail_url" mode="aspectFill" />
|
||||
<view v-else class="attachment-video-thumb">
|
||||
<text class="attachment-video-label">视频</text>
|
||||
</view>
|
||||
</template>
|
||||
<view v-else class="attachment-file-thumb">{{ assetTypeLabel(item) }}</view>
|
||||
<view v-if="isVideoAsset(item)" class="attachment-play" @click.stop="openAsset(item)">▶</view>
|
||||
</view>
|
||||
<view class="attachment-name">{{ item.name || item.file_id }}</view>
|
||||
<text class="attachment-type">{{ assetTypeLabel(item) }}</text>
|
||||
</view>
|
||||
</view>
|
||||
<view v-else class="empty" style="padding: 24rpx 0">暂无证据附件</view>
|
||||
</view>
|
||||
|
||||
<view v-if="zhongjianReportFiles.length" class="card">
|
||||
<view class="card-title">中检报告文件</view>
|
||||
<view class="attachment-grid">
|
||||
<view v-for="item in zhongjianReportFiles" :key="item.file_url || item.file_id" class="attachment-tile">
|
||||
<view class="attachment-preview" @click="openAsset(item)">
|
||||
<image v-if="isImageAsset(item)" class="attachment-thumb" :src="item.thumbnail_url || item.file_url" mode="aspectFill" />
|
||||
<template v-else-if="isVideoAsset(item)">
|
||||
<image v-if="item.thumbnail_url" class="attachment-thumb" :src="item.thumbnail_url" mode="aspectFill" />
|
||||
<view v-else class="attachment-video-thumb">
|
||||
<text class="attachment-video-label">视频</text>
|
||||
</view>
|
||||
</template>
|
||||
<view v-else class="attachment-file-thumb">{{ assetTypeLabel(item) }}</view>
|
||||
<view v-if="isVideoAsset(item)" class="attachment-play" @click.stop="openAsset(item)">▶</view>
|
||||
</view>
|
||||
<view class="attachment-name">{{ item.name || item.file_id }}</view>
|
||||
<text class="attachment-type">{{ assetTypeLabel(item) }}</text>
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
|
||||
<view v-if="activeVideo" class="video-preview-mask" @click="closeVideo">
|
||||
<view class="video-preview-panel" @click.stop>
|
||||
<view class="video-preview-head">
|
||||
@@ -347,111 +416,457 @@ onShow(() => {
|
||||
</template>
|
||||
|
||||
<style scoped lang="scss">
|
||||
.list {
|
||||
display: grid;
|
||||
gap: 14rpx;
|
||||
.report-page {
|
||||
width: 100vw;
|
||||
max-width: 100vw;
|
||||
padding: 28rpx 32rpx 48rpx;
|
||||
overflow-x: hidden;
|
||||
background: #f1f3f6;
|
||||
color: #3c3f45;
|
||||
}
|
||||
|
||||
.return-review-card {
|
||||
border-color: var(--work-accent);
|
||||
.report-page--with-action {
|
||||
padding-bottom: 150rpx;
|
||||
}
|
||||
|
||||
.main-action {
|
||||
margin-top: 18rpx;
|
||||
.notice-card {
|
||||
padding: 42rpx 34rpx;
|
||||
border-radius: 22rpx;
|
||||
background: #ffffff;
|
||||
box-shadow: 0 18rpx 48rpx rgba(31, 36, 48, 0.08);
|
||||
}
|
||||
|
||||
.attachment-grid {
|
||||
display: grid;
|
||||
grid-template-columns: repeat(3, minmax(0, 1fr));
|
||||
gap: 14rpx;
|
||||
margin-top: 18rpx;
|
||||
.notice-card__title {
|
||||
color: #2f3238;
|
||||
font-size: 32rpx;
|
||||
font-weight: 800;
|
||||
line-height: 1.35;
|
||||
}
|
||||
|
||||
.attachment-tile {
|
||||
.notice-card__desc {
|
||||
margin-top: 12rpx;
|
||||
color: #7e838b;
|
||||
font-size: 26rpx;
|
||||
line-height: 1.55;
|
||||
}
|
||||
|
||||
.review-strip {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: space-between;
|
||||
gap: 22rpx;
|
||||
margin-bottom: 22rpx;
|
||||
padding: 22rpx 24rpx;
|
||||
border: 1px solid rgba(223, 183, 51, 0.34);
|
||||
border-radius: 18rpx;
|
||||
background: #fff9e6;
|
||||
}
|
||||
|
||||
.review-strip__title {
|
||||
color: #3d3f44;
|
||||
font-size: 28rpx;
|
||||
font-weight: 800;
|
||||
line-height: 1.35;
|
||||
}
|
||||
|
||||
.review-strip__desc {
|
||||
margin-top: 6rpx;
|
||||
color: #7b6c3e;
|
||||
font-size: 23rpx;
|
||||
line-height: 1.45;
|
||||
}
|
||||
|
||||
.review-strip__tag {
|
||||
flex: 0 0 auto;
|
||||
min-height: 38rpx;
|
||||
padding: 0 14rpx;
|
||||
border-radius: 999rpx;
|
||||
background: #ffffff;
|
||||
color: #9f8433;
|
||||
font-size: 22rpx;
|
||||
font-weight: 800;
|
||||
line-height: 38rpx;
|
||||
}
|
||||
|
||||
.report-shell {
|
||||
position: relative;
|
||||
overflow: hidden;
|
||||
border-radius: 28rpx;
|
||||
background: #ffffff;
|
||||
box-shadow: 0 18rpx 48rpx rgba(31, 36, 48, 0.08);
|
||||
}
|
||||
|
||||
.report-cover {
|
||||
height: 356rpx;
|
||||
margin: 28rpx 28rpx 0;
|
||||
overflow: hidden;
|
||||
border-radius: 10rpx;
|
||||
background: #e8eaee;
|
||||
}
|
||||
|
||||
.report-cover__swiper,
|
||||
.report-cover__image,
|
||||
.report-cover__empty {
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
}
|
||||
|
||||
.report-cover__image {
|
||||
display: block;
|
||||
}
|
||||
|
||||
.report-cover__empty {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
color: #8c919b;
|
||||
font-size: 24rpx;
|
||||
}
|
||||
|
||||
.report-meta {
|
||||
padding: 34rpx 28rpx 12rpx;
|
||||
}
|
||||
|
||||
.report-meta__row {
|
||||
display: flex;
|
||||
align-items: flex-start;
|
||||
gap: 18rpx;
|
||||
min-width: 0;
|
||||
min-height: 48rpx;
|
||||
}
|
||||
|
||||
.report-meta__row + .report-meta__row {
|
||||
margin-top: 20rpx;
|
||||
}
|
||||
|
||||
.report-meta__label {
|
||||
flex: 0 0 138rpx;
|
||||
display: block;
|
||||
color: #7d828a;
|
||||
font-size: 28rpx;
|
||||
line-height: 1.4;
|
||||
}
|
||||
|
||||
.report-meta__value {
|
||||
flex: 1;
|
||||
display: block;
|
||||
min-width: 0;
|
||||
color: #44474d;
|
||||
font-size: 28rpx;
|
||||
font-weight: 700;
|
||||
line-height: 1.35;
|
||||
text-align: right;
|
||||
white-space: normal;
|
||||
word-break: break-all;
|
||||
overflow-wrap: anywhere;
|
||||
}
|
||||
|
||||
.report-meta__row--date .report-meta__value {
|
||||
flex: 0 1 auto;
|
||||
margin-left: auto;
|
||||
word-break: normal;
|
||||
}
|
||||
|
||||
.report-meta__tag {
|
||||
flex: 0 0 auto;
|
||||
display: block;
|
||||
min-height: 38rpx;
|
||||
padding: 0 16rpx;
|
||||
border: 1px solid rgba(221, 179, 47, 0.74);
|
||||
border-radius: 6rpx;
|
||||
background: #fff9e6;
|
||||
color: #9f8433;
|
||||
font-size: 22rpx;
|
||||
font-weight: 700;
|
||||
line-height: 36rpx;
|
||||
}
|
||||
|
||||
.report-tabs {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
gap: 104rpx;
|
||||
padding: 26rpx 40rpx 34rpx;
|
||||
}
|
||||
|
||||
.report-tab {
|
||||
position: relative;
|
||||
color: #8e9298;
|
||||
font-size: 32rpx;
|
||||
font-weight: 700;
|
||||
line-height: 1.6;
|
||||
}
|
||||
|
||||
.report-tab--active {
|
||||
color: var(--work-accent);
|
||||
}
|
||||
|
||||
.report-tab--active::after {
|
||||
position: absolute;
|
||||
left: 50%;
|
||||
bottom: -10rpx;
|
||||
width: 44rpx;
|
||||
height: 6rpx;
|
||||
border-radius: 999rpx;
|
||||
background: var(--work-accent);
|
||||
content: "";
|
||||
transform: translateX(-50%);
|
||||
}
|
||||
|
||||
.report-panel {
|
||||
position: relative;
|
||||
min-height: 440rpx;
|
||||
padding: 18rpx 28rpx 48rpx;
|
||||
overflow: hidden;
|
||||
}
|
||||
|
||||
.report-watermark {
|
||||
position: absolute;
|
||||
top: -6rpx;
|
||||
left: 50%;
|
||||
width: 520rpx;
|
||||
height: 430rpx;
|
||||
border-radius: 50%;
|
||||
opacity: 0.46;
|
||||
transform: translateX(-50%);
|
||||
background:
|
||||
repeating-radial-gradient(ellipse at center, rgba(230, 195, 79, 0.2) 0, rgba(230, 195, 79, 0.2) 2rpx, transparent 3rpx, transparent 17rpx),
|
||||
repeating-conic-gradient(from 0deg, rgba(230, 195, 79, 0.12) 0deg 8deg, transparent 8deg 16deg);
|
||||
pointer-events: none;
|
||||
}
|
||||
|
||||
.report-result {
|
||||
position: relative;
|
||||
z-index: 1;
|
||||
display: flex;
|
||||
align-items: flex-start;
|
||||
gap: 24rpx;
|
||||
padding: 10rpx 0 30rpx;
|
||||
border-bottom: 1px solid #e5e5e5;
|
||||
}
|
||||
|
||||
.report-result__content {
|
||||
flex: 1;
|
||||
min-width: 0;
|
||||
}
|
||||
|
||||
.attachment-preview {
|
||||
position: relative;
|
||||
width: 100%;
|
||||
aspect-ratio: 1;
|
||||
overflow: hidden;
|
||||
border: 1px solid var(--work-border);
|
||||
border-radius: var(--work-radius-sm);
|
||||
background: var(--work-card-muted);
|
||||
.report-result__label {
|
||||
color: #3d3f44;
|
||||
font-size: 28rpx;
|
||||
font-weight: 800;
|
||||
line-height: 1.45;
|
||||
}
|
||||
|
||||
.attachment-thumb {
|
||||
.report-result__value {
|
||||
margin-top: 14rpx;
|
||||
color: #e04135;
|
||||
font-size: 38rpx;
|
||||
font-weight: 900;
|
||||
line-height: 1.22;
|
||||
letter-spacing: 0;
|
||||
}
|
||||
|
||||
.report-result__desc {
|
||||
margin-top: 10rpx;
|
||||
color: #6f747c;
|
||||
font-size: 24rpx;
|
||||
line-height: 1.55;
|
||||
}
|
||||
|
||||
.report-seal {
|
||||
flex: 0 0 auto;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
width: 104rpx;
|
||||
height: 104rpx;
|
||||
margin-top: 2rpx;
|
||||
border: 4rpx solid rgba(56, 164, 73, 0.8);
|
||||
border-radius: 999rpx;
|
||||
color: #39a54b;
|
||||
transform: rotate(-10deg);
|
||||
}
|
||||
|
||||
.report-seal__brand {
|
||||
font-size: 16rpx;
|
||||
font-weight: 800;
|
||||
line-height: 1;
|
||||
}
|
||||
|
||||
.report-seal__main {
|
||||
margin-top: 8rpx;
|
||||
font-size: 28rpx;
|
||||
font-weight: 900;
|
||||
line-height: 1;
|
||||
}
|
||||
|
||||
.product-spec {
|
||||
position: relative;
|
||||
z-index: 1;
|
||||
padding-top: 20rpx;
|
||||
}
|
||||
|
||||
.product-spec__row {
|
||||
display: flex;
|
||||
flex-wrap: wrap;
|
||||
align-items: center;
|
||||
gap: 10rpx;
|
||||
min-height: 54rpx;
|
||||
}
|
||||
|
||||
.product-spec__label {
|
||||
flex: 0 0 auto;
|
||||
display: block;
|
||||
color: #858991;
|
||||
font-size: 24rpx;
|
||||
line-height: 1.4;
|
||||
}
|
||||
|
||||
.product-spec__line {
|
||||
flex: 1;
|
||||
min-width: 32rpx;
|
||||
height: 1px;
|
||||
border-bottom: 1px dotted #b9bdc4;
|
||||
}
|
||||
|
||||
.product-spec__value {
|
||||
flex: 0 1 auto;
|
||||
display: block;
|
||||
max-width: 58%;
|
||||
color: #5b5f67;
|
||||
font-size: 24rpx;
|
||||
font-weight: 700;
|
||||
line-height: 1.4;
|
||||
text-align: right;
|
||||
word-break: break-all;
|
||||
overflow-wrap: anywhere;
|
||||
}
|
||||
|
||||
.product-spec__remark {
|
||||
flex-basis: 100%;
|
||||
display: block;
|
||||
margin: -2rpx 0 12rpx 0;
|
||||
color: #8b9098;
|
||||
font-size: 22rpx;
|
||||
line-height: 1.45;
|
||||
}
|
||||
|
||||
.report-panel--attachments {
|
||||
padding-top: 2rpx;
|
||||
}
|
||||
|
||||
.inline-section {
|
||||
position: relative;
|
||||
z-index: 1;
|
||||
padding-top: 24rpx;
|
||||
border-top: 1px solid #ececec;
|
||||
}
|
||||
|
||||
.inline-section + .inline-section {
|
||||
margin-top: 30rpx;
|
||||
}
|
||||
|
||||
.inline-section:first-child {
|
||||
padding-top: 0;
|
||||
border-top: 0;
|
||||
}
|
||||
|
||||
.inline-section__title {
|
||||
color: #3f4248;
|
||||
font-size: 28rpx;
|
||||
font-weight: 800;
|
||||
}
|
||||
|
||||
.attachment-empty {
|
||||
padding: 58rpx 0;
|
||||
color: #8b9098;
|
||||
font-size: 26rpx;
|
||||
text-align: center;
|
||||
}
|
||||
|
||||
.attachment-empty--compact {
|
||||
padding: 24rpx 0 0;
|
||||
text-align: left;
|
||||
}
|
||||
|
||||
.asset-grid {
|
||||
display: grid;
|
||||
grid-template-columns: repeat(3, minmax(0, 1fr));
|
||||
gap: 12rpx;
|
||||
margin-top: 18rpx;
|
||||
}
|
||||
|
||||
.asset-tile {
|
||||
position: relative;
|
||||
aspect-ratio: 1;
|
||||
overflow: hidden;
|
||||
border: 1px solid rgba(127, 119, 94, 0.16);
|
||||
border-radius: 8rpx;
|
||||
background: #f5f3ee;
|
||||
}
|
||||
|
||||
.asset-tile__image {
|
||||
display: block;
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
}
|
||||
|
||||
.attachment-video-thumb,
|
||||
.attachment-file-thumb {
|
||||
.asset-list {
|
||||
display: grid;
|
||||
gap: 12rpx;
|
||||
margin-top: 18rpx;
|
||||
}
|
||||
|
||||
.asset-list__item {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
}
|
||||
|
||||
.attachment-video-thumb {
|
||||
background: linear-gradient(135deg, #f8fafc 0%, #e8edf3 100%);
|
||||
color: var(--work-text);
|
||||
}
|
||||
|
||||
.attachment-video-label {
|
||||
font-size: 24rpx;
|
||||
font-weight: 900;
|
||||
}
|
||||
|
||||
.attachment-file-thumb {
|
||||
color: var(--work-text-soft);
|
||||
font-size: 24rpx;
|
||||
font-weight: 800;
|
||||
}
|
||||
|
||||
.attachment-play {
|
||||
position: absolute;
|
||||
left: 50%;
|
||||
top: 50%;
|
||||
width: 54rpx;
|
||||
height: 54rpx;
|
||||
margin-left: -27rpx;
|
||||
margin-top: -27rpx;
|
||||
border-radius: 50%;
|
||||
background: rgba(32, 33, 36, 0.72);
|
||||
color: #ffffff;
|
||||
font-size: 28rpx;
|
||||
line-height: 54rpx;
|
||||
text-align: center;
|
||||
}
|
||||
|
||||
.attachment-name {
|
||||
min-width: 0;
|
||||
margin-top: 8rpx;
|
||||
overflow: hidden;
|
||||
color: var(--work-text);
|
||||
font-size: 22rpx;
|
||||
justify-content: space-between;
|
||||
gap: 16rpx;
|
||||
padding: 18rpx;
|
||||
border-radius: 8rpx;
|
||||
background: #faf8f1;
|
||||
color: #3f4248;
|
||||
font-size: 26rpx;
|
||||
font-weight: 700;
|
||||
line-height: 1.35;
|
||||
}
|
||||
|
||||
.asset-list__item text:first-child {
|
||||
min-width: 0;
|
||||
overflow: hidden;
|
||||
text-overflow: ellipsis;
|
||||
white-space: nowrap;
|
||||
}
|
||||
|
||||
.attachment-type {
|
||||
display: inline-flex;
|
||||
.asset-list__type {
|
||||
flex: 0 0 auto;
|
||||
color: var(--work-accent);
|
||||
}
|
||||
|
||||
.report-actions {
|
||||
position: fixed;
|
||||
z-index: 18;
|
||||
left: 0;
|
||||
right: 0;
|
||||
bottom: 0;
|
||||
width: 100vw;
|
||||
box-sizing: border-box;
|
||||
padding: 22rpx 32rpx calc(22rpx + env(safe-area-inset-bottom));
|
||||
background: rgba(241, 243, 246, 0.96);
|
||||
box-shadow: 0 -10rpx 34rpx rgba(31, 36, 48, 0.05);
|
||||
}
|
||||
|
||||
.report-actions__button {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
min-height: 34rpx;
|
||||
margin-top: 6rpx;
|
||||
padding: 0 10rpx;
|
||||
border-radius: var(--work-radius-pill);
|
||||
background: var(--work-info-soft);
|
||||
color: var(--work-info);
|
||||
font-size: 20rpx;
|
||||
font-weight: 700;
|
||||
line-height: 34rpx;
|
||||
justify-content: center;
|
||||
width: 100%;
|
||||
min-height: 82rpx;
|
||||
border-radius: 999rpx;
|
||||
background: #dfb733;
|
||||
color: #ffffff;
|
||||
font-size: 28rpx;
|
||||
font-weight: 800;
|
||||
line-height: 82rpx;
|
||||
}
|
||||
|
||||
.video-preview-mask {
|
||||
|
||||
Reference in New Issue
Block a user