feat: update appraisal return address and test packaging assets
This commit is contained in:
@@ -199,6 +199,12 @@ export interface AdminManualOrderMeta {
|
||||
}>;
|
||||
}
|
||||
|
||||
export interface AdminCatalogCategoryOption {
|
||||
id: number;
|
||||
name: string;
|
||||
code: string;
|
||||
}
|
||||
|
||||
export interface AdminOrderDetail {
|
||||
order_info: AdminOrderListItem & {
|
||||
can_mark_received: boolean;
|
||||
@@ -541,6 +547,25 @@ export const adminApi = {
|
||||
getManualOrderMeta() {
|
||||
return request<AdminManualOrderMeta>("/api/admin/manual-order/meta");
|
||||
},
|
||||
async getAppCatalogCategories() {
|
||||
const data = await request<{
|
||||
category_entries: Array<{
|
||||
category_id: number;
|
||||
category_name: string;
|
||||
category_code: string;
|
||||
}>;
|
||||
}>("/api/app/home/index");
|
||||
|
||||
const list: AdminCatalogCategoryOption[] = data.category_entries.map((item) => ({
|
||||
id: item.category_id,
|
||||
name: item.category_name,
|
||||
code: item.category_code,
|
||||
}));
|
||||
|
||||
return {
|
||||
list,
|
||||
};
|
||||
},
|
||||
getExpressCompanies(params: { enabled_only?: 0 | 1 } = { enabled_only: 1 }) {
|
||||
return request<{ list: AdminExpressCompanyItem[]; default_company: string }>("/api/admin/express-companies", { params });
|
||||
},
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
<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 { adminApi, type AdminAppraisalTaskDetail, type AdminCatalogCategoryOption, type AdminFileAsset } from "../../api/admin";
|
||||
import { showErrorToast, showInfoToast, withLoading } from "../../utils/feedback";
|
||||
|
||||
const loading = ref(false);
|
||||
@@ -25,6 +25,7 @@ const externalRemark = ref("");
|
||||
const internalRemark = ref("");
|
||||
const zhongjianReportNo = ref("");
|
||||
const productName = ref("");
|
||||
const categoryId = ref(0);
|
||||
const categoryName = ref("");
|
||||
const brandName = ref("");
|
||||
const color = ref("");
|
||||
@@ -33,6 +34,8 @@ const serialNo = ref("");
|
||||
const zhongjianFiles = ref<AdminFileAsset[]>([]);
|
||||
const evidenceFiles = ref<AdminFileAsset[]>([]);
|
||||
const activePreviewVideo = ref<AdminFileAsset | null>(null);
|
||||
const catalogCategories = ref<AdminCatalogCategoryOption[]>([]);
|
||||
const categoryLoading = ref(false);
|
||||
const supplementForm = reactive({
|
||||
reason: "",
|
||||
deadline: "",
|
||||
@@ -56,6 +59,13 @@ const internalTagNo = computed(() => detail.value?.task_info.internal_tag_no ||
|
||||
const resultSummary = computed(() => detail.value?.result_info.result_text || "暂未填写");
|
||||
const reportSummary = computed(() => detail.value?.report_summary?.report_no || "");
|
||||
const hasBoundMaterialTag = computed(() => Boolean(detail.value?.material_tag?.id));
|
||||
const categoryOptions = computed(() => catalogCategories.value);
|
||||
const categoryPickerIndex = computed(() => Math.max(0, categoryOptions.value.findIndex((item) => item.id === categoryId.value)));
|
||||
const categoryPickerLabel = computed(() => selectedCategoryName(categoryId.value) || categoryName.value.trim());
|
||||
const categoryPickerPlaceholder = computed(() => {
|
||||
if (categoryLoading.value) return "正在加载品类";
|
||||
return categoryOptions.value.length ? "请选择品类" : "暂无可选品类";
|
||||
});
|
||||
type AppraisalTemplate = NonNullable<AdminAppraisalTaskDetail["appraisal_template"]>;
|
||||
|
||||
function hasConditionFields(template?: AppraisalTemplate | null) {
|
||||
@@ -74,6 +84,58 @@ function formatMoneyInput(value: string | number) {
|
||||
return Number.isFinite(num) ? num : 0;
|
||||
}
|
||||
|
||||
function selectedCategoryName(selectedCategoryId: number) {
|
||||
return categoryOptions.value.find((item) => item.id === selectedCategoryId)?.name || "";
|
||||
}
|
||||
|
||||
function resolveCategoryId(selectedCategoryId: number, selectedCategoryNameText: string) {
|
||||
if (selectedCategoryId) return selectedCategoryId;
|
||||
const categoryNameText = selectedCategoryNameText.trim();
|
||||
return categoryOptions.value.find((item) => item.name === categoryNameText)?.id || 0;
|
||||
}
|
||||
|
||||
function syncCurrentCategory() {
|
||||
const resolvedCategoryId = resolveCategoryId(categoryId.value, categoryName.value);
|
||||
categoryId.value = resolvedCategoryId;
|
||||
categoryName.value = selectedCategoryName(resolvedCategoryId) || categoryName.value;
|
||||
}
|
||||
|
||||
async function fetchCatalogMeta() {
|
||||
if (catalogCategories.value.length || categoryLoading.value) return;
|
||||
categoryLoading.value = true;
|
||||
try {
|
||||
const data = await adminApi.getAppCatalogCategories();
|
||||
catalogCategories.value = data.list;
|
||||
syncCurrentCategory();
|
||||
} catch (error) {
|
||||
showErrorToast(error, "品类列表加载失败");
|
||||
} finally {
|
||||
categoryLoading.value = false;
|
||||
}
|
||||
}
|
||||
|
||||
function onCategoryChange(event: any) {
|
||||
if (isTaskReadonly.value) return;
|
||||
const index = Number(event.detail?.value || 0);
|
||||
const category = categoryOptions.value[index];
|
||||
if (!category) return;
|
||||
categoryId.value = category.id;
|
||||
categoryName.value = category.name;
|
||||
}
|
||||
|
||||
function productInfoPayload() {
|
||||
const resolvedCategoryId = resolveCategoryId(categoryId.value, categoryName.value);
|
||||
return {
|
||||
category_id: resolvedCategoryId,
|
||||
product_name: productName.value.trim(),
|
||||
category_name: selectedCategoryName(resolvedCategoryId) || categoryName.value.trim(),
|
||||
brand_name: brandName.value.trim(),
|
||||
color: color.value.trim(),
|
||||
size_spec: sizeSpec.value.trim(),
|
||||
serial_no: serialNo.value.trim(),
|
||||
};
|
||||
}
|
||||
|
||||
function hydrate(detailData: AdminAppraisalTaskDetail) {
|
||||
detail.value = detailData;
|
||||
activeSection.value = detailData.task_info.service_provider === "zhongjian"
|
||||
@@ -102,7 +164,9 @@ function hydrate(detailData: AdminAppraisalTaskDetail) {
|
||||
internalRemark.value = detailData.result_info.internal_remark || "";
|
||||
zhongjianReportNo.value = detailData.zhongjian_report?.report_no || "";
|
||||
productName.value = detailData.product_info.product_name || "";
|
||||
categoryId.value = resolveCategoryId(detailData.product_info.category_id, detailData.product_info.category_name || "");
|
||||
categoryName.value = detailData.product_info.category_name || "";
|
||||
syncCurrentCategory();
|
||||
brandName.value = detailData.product_info.brand_name || "";
|
||||
color.value = detailData.product_info.color || "";
|
||||
sizeSpec.value = detailData.product_info.size_spec || "";
|
||||
@@ -556,15 +620,7 @@ async function submitResult(action: "save" | "submit") {
|
||||
adminApi.saveAppraisalTaskResult({
|
||||
id: detail.value!.task_info.id,
|
||||
action,
|
||||
product_info: {
|
||||
category_id: detail.value!.product_info.category_id,
|
||||
product_name: productName.value.trim(),
|
||||
category_name: categoryName.value.trim(),
|
||||
brand_name: brandName.value.trim(),
|
||||
color: color.value.trim(),
|
||||
size_spec: sizeSpec.value.trim(),
|
||||
serial_no: serialNo.value.trim(),
|
||||
},
|
||||
product_info: productInfoPayload(),
|
||||
result_text: resultText.value.trim(),
|
||||
result_desc: resultDesc.value.trim(),
|
||||
...conditionPayload,
|
||||
@@ -662,15 +718,7 @@ async function submitZhongjianReport() {
|
||||
await adminApi.saveZhongjianAppraisalReport({
|
||||
id: detail.value.task_info.id,
|
||||
zhongjian_report_no: zhongjianReportNo.value.trim(),
|
||||
product_info: {
|
||||
category_id: detail.value.product_info.category_id,
|
||||
product_name: productName.value.trim(),
|
||||
category_name: categoryName.value.trim(),
|
||||
brand_name: brandName.value.trim(),
|
||||
color: color.value.trim(),
|
||||
size_spec: sizeSpec.value.trim(),
|
||||
serial_no: serialNo.value.trim(),
|
||||
},
|
||||
product_info: productInfoPayload(),
|
||||
result_text: resultText.value.trim(),
|
||||
result_desc: resultDesc.value.trim(),
|
||||
attachments: evidenceFiles.value,
|
||||
@@ -700,8 +748,11 @@ onLoad((options) => {
|
||||
});
|
||||
|
||||
onShow(() => {
|
||||
if (taskId.value && !pageReady.value) {
|
||||
void fetchDetail();
|
||||
if (taskId.value) {
|
||||
void fetchCatalogMeta();
|
||||
if (!pageReady.value) {
|
||||
void fetchDetail();
|
||||
}
|
||||
}
|
||||
});
|
||||
</script>
|
||||
@@ -767,7 +818,19 @@ onShow(() => {
|
||||
<view class="stack" style="margin-top: 18rpx">
|
||||
<view class="card-desc">报告展示信息</view>
|
||||
<input v-model="productName" class="field" :disabled="isTaskReadonly" placeholder="产品名称" />
|
||||
<input v-model="categoryName" class="field" :disabled="isTaskReadonly" placeholder="品类" />
|
||||
<picker
|
||||
:range="categoryOptions"
|
||||
range-key="name"
|
||||
:value="categoryPickerIndex"
|
||||
:disabled="isTaskReadonly || categoryLoading || !categoryOptions.length"
|
||||
@change="onCategoryChange"
|
||||
>
|
||||
<view class="field picker-field" :class="{ 'picker-field--disabled': isTaskReadonly }">
|
||||
<text v-if="categoryPickerLabel" class="picker-field__value">{{ categoryPickerLabel }}</text>
|
||||
<text v-else class="picker-field__placeholder">{{ categoryPickerPlaceholder }}</text>
|
||||
<text v-if="!isTaskReadonly" class="picker-field__arrow"></text>
|
||||
</view>
|
||||
</picker>
|
||||
<input v-model="brandName" class="field" :disabled="isTaskReadonly" placeholder="品牌" />
|
||||
<view class="meta-grid">
|
||||
<input v-model="color" class="field" :disabled="isTaskReadonly" placeholder="颜色" />
|
||||
@@ -876,7 +939,19 @@ onShow(() => {
|
||||
<view class="stack" style="margin-top: 18rpx">
|
||||
<view class="card-desc">报告展示信息</view>
|
||||
<input v-model="productName" class="field" :disabled="isTaskReadonly" placeholder="产品名称" />
|
||||
<input v-model="categoryName" class="field" :disabled="isTaskReadonly" placeholder="品类" />
|
||||
<picker
|
||||
:range="categoryOptions"
|
||||
range-key="name"
|
||||
:value="categoryPickerIndex"
|
||||
:disabled="isTaskReadonly || categoryLoading || !categoryOptions.length"
|
||||
@change="onCategoryChange"
|
||||
>
|
||||
<view class="field picker-field" :class="{ 'picker-field--disabled': isTaskReadonly }">
|
||||
<text v-if="categoryPickerLabel" class="picker-field__value">{{ categoryPickerLabel }}</text>
|
||||
<text v-else class="picker-field__placeholder">{{ categoryPickerPlaceholder }}</text>
|
||||
<text v-if="!isTaskReadonly" class="picker-field__arrow"></text>
|
||||
</view>
|
||||
</picker>
|
||||
<input v-model="brandName" class="field" :disabled="isTaskReadonly" placeholder="品牌" />
|
||||
<view class="meta-grid">
|
||||
<input v-model="color" class="field" :disabled="isTaskReadonly" placeholder="颜色" />
|
||||
@@ -1051,6 +1126,42 @@ onShow(() => {
|
||||
font-weight: 800;
|
||||
}
|
||||
|
||||
.picker-field {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: space-between;
|
||||
gap: 16rpx;
|
||||
}
|
||||
|
||||
.picker-field--disabled {
|
||||
opacity: 0.82;
|
||||
}
|
||||
|
||||
.picker-field__value,
|
||||
.picker-field__placeholder {
|
||||
min-width: 0;
|
||||
overflow: hidden;
|
||||
text-overflow: ellipsis;
|
||||
white-space: nowrap;
|
||||
}
|
||||
|
||||
.picker-field__value {
|
||||
color: var(--work-text);
|
||||
}
|
||||
|
||||
.picker-field__placeholder {
|
||||
color: var(--work-text-muted);
|
||||
}
|
||||
|
||||
.picker-field__arrow {
|
||||
width: 14rpx;
|
||||
height: 14rpx;
|
||||
flex: 0 0 14rpx;
|
||||
border-right: 3rpx solid var(--work-text-soft);
|
||||
border-bottom: 3rpx solid var(--work-text-soft);
|
||||
transform: rotate(45deg);
|
||||
}
|
||||
|
||||
.attachment-grid {
|
||||
display: grid;
|
||||
grid-template-columns: repeat(3, minmax(0, 1fr));
|
||||
|
||||
Reference in New Issue
Block a user