chore: release updated anxinyan version

This commit is contained in:
wushumin
2026-05-22 21:13:52 +08:00
parent 7e86e2a5ec
commit 78098851f9
29 changed files with 1949 additions and 184 deletions

View File

@@ -3,13 +3,15 @@ import { computed, ref } from "vue";
import { onLoad } from "@dcloudio/uni-app";
import { adminApi, type AdminManualOrderCreatePayload, type AdminManualOrderMeta } from "../../api/admin";
import { showErrorToast, showInfoToast, withLoading } from "../../utils/feedback";
import { buildRegionPickerState, updateRegionPickerIndexes } from "../../utils/regions";
import { recognizeReturnAddress } from "../../utils/address-recognition";
import { buildRegionPickerState, findRegionIndexes, updateRegionPickerIndexes } from "../../utils/regions";
const loading = ref(false);
const submitting = ref(false);
const meta = ref<AdminManualOrderMeta>({ categories: [], brands: [] });
const form = ref<AdminManualOrderCreatePayload>(createForm());
const regionPickerIndexes = ref<[number, number, number]>([0, 0, 0]);
const addressRecognitionText = ref("");
const providerOptions = [
{ label: "实物鉴定", value: "anxinyan" },
@@ -110,6 +112,21 @@ function pickerText(options: Array<{ label?: string; name?: string }>, index: nu
return item?.label || item?.name || fallback;
}
function applyRecognizedReturnAddress() {
const result = recognizeReturnAddress(addressRecognitionText.value);
if (!result.ok || !result.address) {
showInfoToast(result.message || "寄回地址识别失败");
return;
}
form.value.return_address = {
...form.value.return_address,
...result.address,
};
regionPickerIndexes.value = findRegionIndexes(result.address);
showInfoToast("寄回地址已识别并填入");
}
function validateForm() {
const product = form.value.product_info;
const address = form.value.return_address;
@@ -173,6 +190,14 @@ onLoad(() => {
<view class="card stack">
<view class="card-title">寄回信息</view>
<view class="address-recognition">
<textarea
v-model="addressRecognitionText"
class="textarea address-recognition__textarea"
placeholder="粘贴收货人、收货电话、收货地址,自动识别后填入下方字段"
/>
<button class="btn btn--ghost address-recognition__button" @click="applyRecognizedReturnAddress">识别并填入</button>
</view>
<input v-model="form.return_address.consignee" class="field" placeholder="收件人" />
<input v-model="form.return_address.mobile" class="field" type="number" placeholder="手机号,用于匹配用户" />
<picker
@@ -216,6 +241,19 @@ onLoad(() => {
line-height: 1.4;
}
.address-recognition {
display: grid;
gap: 12rpx;
}
.address-recognition__textarea {
min-height: 188rpx;
}
.address-recognition__button {
justify-self: stretch;
}
.region-field {
justify-content: space-between;
gap: 16rpx;

View File

@@ -48,7 +48,7 @@ const resultMetaItems = computed(() => {
for (const point of normalizedKeyPoints(result.key_points)) {
items.push({
label: point.point_name,
value: [point.point_value, point.point_remark].filter(Boolean).join("") || "-",
value: point.point_value || "-",
});
}
@@ -97,7 +97,7 @@ function normalizedKeyPoints(value: unknown) {
point_remark: textValue(point.point_remark),
};
})
.filter((item) => item.point_value || item.point_remark);
.filter((item) => item.point_value);
}
function isImageAsset(item: AdminFileAsset) {

View File

@@ -1,12 +1,15 @@
<script setup lang="ts">
import { computed, ref } from "vue";
import { onLoad } from "@dcloudio/uni-app";
import { adminApi, type AdminFileAsset, type AdminWarehouseWorkbenchContext } from "../../api/admin";
import { adminApi, type AdminExpressCompanyItem, type AdminFileAsset, type AdminWarehouseWorkbenchContext } from "../../api/admin";
import { showErrorToast, showInfoToast, withLoading } from "../../utils/feedback";
const internalTagNo = ref("");
const expressCompany = ref("");
const trackingNo = ref("");
const expressCompanyOptions = ref<AdminExpressCompanyItem[]>([]);
const expressCompanyLoading = ref(false);
const defaultExpressCompany = ref("");
const context = ref<AdminWarehouseWorkbenchContext | null>(null);
const loading = ref(false);
const submitting = ref(false);
@@ -16,6 +19,14 @@ const activeVideo = ref<AdminFileAsset | null>(null);
const RETURN_SHIPPED_STORAGE_KEY = "warehouse_return_shipped_context";
const returnConfirmed = computed(() => Boolean(context.value?.transfer_flow?.return_confirmed_at));
const expressCompanyNames = computed(() => {
const names = expressCompanyOptions.value.map((item) => item.company_name);
if (expressCompany.value && !names.includes(expressCompany.value)) {
return [expressCompany.value, ...names];
}
return names;
});
const expressCompanyIndex = computed(() => Math.max(0, expressCompanyNames.value.findIndex((item) => item === expressCompany.value)));
const canSubmit = computed(() =>
returnConfirmed.value &&
Boolean(expressCompany.value.trim()) &&
@@ -53,6 +64,27 @@ async function fetchContext() {
}
}
async function fetchExpressCompanies() {
expressCompanyLoading.value = true;
try {
const response = await adminApi.getExpressCompanies({ enabled_only: 1 });
expressCompanyOptions.value = response.list;
defaultExpressCompany.value = response.default_company;
if (!expressCompany.value) {
expressCompany.value = response.default_company || response.list[0]?.company_name || "";
}
} catch (error) {
showErrorToast(error, "快递公司列表加载失败");
} finally {
expressCompanyLoading.value = false;
}
}
function onExpressCompanyChange(event: any) {
const index = Number(event.detail?.value || 0);
expressCompany.value = expressCompanyNames.value[index] || "";
}
function scanTrackingNo() {
uni.scanCode({
scanType: ["barCode", "qrCode"],
@@ -189,6 +221,7 @@ async function submitReturnShipping() {
onLoad((options) => {
internalTagNo.value = readQueryString(options?.internal_tag_no);
void fetchExpressCompanies();
void fetchContext();
});
</script>
@@ -241,7 +274,13 @@ onLoad((options) => {
<view class="card">
<view class="card-title">快递单号</view>
<view class="card-desc">报告确认后登记回寄物流信息</view>
<input v-model="expressCompany" class="field form-field" placeholder="回寄快递公司,例如:顺丰速运" />
<picker :range="expressCompanyNames" :value="expressCompanyIndex" @change="onExpressCompanyChange">
<view class="field picker-field form-field">
<text v-if="expressCompany" class="picker-field__value">{{ expressCompany }}</text>
<text v-else class="picker-field__placeholder">{{ expressCompanyLoading ? "正在加载快递公司" : "请选择回寄快递公司" }}</text>
<text class="picker-field__arrow"></text>
</view>
</picker>
<view class="scan-control">
<input v-model="trackingNo" class="field scan-input" placeholder="扫描或输入回寄运单号" />
<button class="btn scan-button" @click="scanTrackingNo">扫码</button>
@@ -305,6 +344,38 @@ onLoad((options) => {
margin-top: 18rpx;
}
.picker-field {
display: flex;
align-items: center;
justify-content: space-between;
gap: 16rpx;
}
.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);
}
.scan-control {
display: flex;
gap: 14rpx;

View File

@@ -269,7 +269,7 @@ function templateKeyPointsPayload() {
point_code: item.point_code,
point_name: item.point_name,
point_value: item.point_value || "",
point_remark: item.point_remark || "",
point_remark: "",
})) || [];
}
@@ -787,13 +787,6 @@ onShow(() => {
:placeholder="`${item.point_name} 值`"
@input="updateTemplatePointFromInput(index, 'point_value', $event)"
/>
<textarea
:value="item.point_remark"
class="textarea"
:disabled="isTaskReadonly"
:placeholder="`${item.point_name} 说明`"
@input="updateTemplatePointFromInput(index, 'point_remark', $event)"
/>
</view>
</view>
@@ -888,13 +881,6 @@ onShow(() => {
:placeholder="`${item.point_name} 值`"
@input="updateTemplatePointFromInput(index, 'point_value', $event)"
/>
<textarea
:value="item.point_remark"
class="textarea"
:disabled="isTaskReadonly"
:placeholder="`${item.point_name} 说明`"
@input="updateTemplatePointFromInput(index, 'point_remark', $event)"
/>
</view>
</view>