feat: 地区选择器改走接口,修复辅料列表 key 重复
静态地区树改为 regionPicker API;新建就诊人异步解析地址;处方辅料列表 :key 改用 index 避免 drug_id 重复。
This commit is contained in:
72
api/regionPicker.js
Normal file
72
api/regionPicker.js
Normal file
@@ -0,0 +1,72 @@
|
||||
/**
|
||||
* 省市区选择器接口(xk-api,取值用 code / result / message,配合 unwrapXkApi)
|
||||
* 按 loginMode 切角色前缀,对齐 upload.js:医生走 region-picker,业务员/平台/诊所管理员走带前缀路由
|
||||
* 为什么:doctor.php 里同名路由只会命中最先注册的医生鉴权组,业务员 token 会被 401
|
||||
*/
|
||||
import { req } from '@/common/js/index.js'
|
||||
|
||||
/**
|
||||
* 按当前登录角色解析 region-picker 前缀与鉴权头标记
|
||||
* @returns {{ prefix: string, header: Record<string, string> }}
|
||||
*/
|
||||
function resolveRegionPickerRoute() {
|
||||
const mode = uni.getStorageSync('loginMode')
|
||||
if (mode === 'salesperson') {
|
||||
return {
|
||||
prefix: '/newApi/salesperson-region-picker/',
|
||||
header: { _salesperson: '1' },
|
||||
}
|
||||
}
|
||||
if (mode === 'platform_admin') {
|
||||
return {
|
||||
prefix: '/newApi/platform-admin-region-picker/',
|
||||
header: { _platformAdmin: '1' },
|
||||
}
|
||||
}
|
||||
if (mode === 'clinic_admin') {
|
||||
return {
|
||||
prefix: '/newApi/clinic-admin-region-picker/',
|
||||
header: { _clinicAdmin: '1' },
|
||||
}
|
||||
}
|
||||
// 医生 / 药师等默认
|
||||
return {
|
||||
prefix: '/newApi/region-picker/',
|
||||
header: {},
|
||||
}
|
||||
}
|
||||
|
||||
function regionPickerRequest(path, data) {
|
||||
const { prefix, header } = resolveRegionPickerRoute()
|
||||
return req.request({
|
||||
url: `${prefix}${path}`,
|
||||
method: 'GET',
|
||||
data,
|
||||
header,
|
||||
})
|
||||
}
|
||||
|
||||
/** 按 pid 拉一层子节点 */
|
||||
export function getRegionChildren(pid = 0) {
|
||||
return regionPickerRequest('children', { pid })
|
||||
}
|
||||
|
||||
/** 地名/首拼/全拼合一搜索 */
|
||||
export function searchRegions(keyword, limit = 30) {
|
||||
return regionPickerRequest('search', { keyword, limit })
|
||||
}
|
||||
|
||||
/** 按省+叶回显 */
|
||||
export function resolveRegionPair(provinceId, cityId) {
|
||||
return regionPickerRequest('resolve', {
|
||||
province_id: provinceId,
|
||||
city_id: cityId,
|
||||
})
|
||||
}
|
||||
|
||||
/** 批量 ID 解析 */
|
||||
export function resolveRegionIds(ids) {
|
||||
return regionPickerRequest('resolve', {
|
||||
ids: (ids || []).join(','),
|
||||
})
|
||||
}
|
||||
@@ -1,632 +1,293 @@
|
||||
import { addressOption } from '@/subPackages/sub_clinic_salesperson/utils/address.js';
|
||||
/**
|
||||
* 省市区选择器状态与组装工具:直连 region-picker API
|
||||
* 对外仍输出 [provinceId, leafId],兼容门店/建就诊人 address 字段
|
||||
* 为什么:本地 addressOption 二级树已废弃,三级树 + 拼音搜索走数据库
|
||||
*/
|
||||
import {
|
||||
getRegionChildren,
|
||||
resolveRegionPair,
|
||||
searchRegions,
|
||||
} from '@/api/regionPicker.js'
|
||||
import { unwrapXkApi } from '@/utils/api-response.js'
|
||||
|
||||
const displayCache = new Map()
|
||||
const pairCache = new Map()
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
/** 跨级搜索结果 */
|
||||
|
||||
|
||||
/** 列表面板统一行 */
|
||||
|
||||
|
||||
const MUNICIPALITY_LABELS = new Set([
|
||||
'北京市',
|
||||
'天津市',
|
||||
'上海市',
|
||||
'重庆市',
|
||||
]);
|
||||
|
||||
let provinceIndexCache = null;
|
||||
|
||||
function isPrefectureCityLabel(label) {
|
||||
return label.endsWith('市') && !label.endsWith('自治区');
|
||||
function cacheKey(provinceId, leafId) {
|
||||
return `${provinceId}_${leafId}`
|
||||
}
|
||||
|
||||
function isDistrictLikeLabel(label) {
|
||||
return /(?:区|县|旗)$/.test(label);
|
||||
function levelFromNumber(level) {
|
||||
if (level <= 1) return 'province'
|
||||
if (level === 2) return 'city'
|
||||
return 'district'
|
||||
}
|
||||
|
||||
function detectMunicipality(province, children) {
|
||||
if (MUNICIPALITY_LABELS.has(province.label)) {
|
||||
return true;
|
||||
}
|
||||
if (!province.label.endsWith('市') || children.length === 0) {
|
||||
return false;
|
||||
}
|
||||
const districtCount = children.filter((c) => isDistrictLikeLabel(c.label)).length;
|
||||
return districtCount / children.length >= 0.8;
|
||||
function toNode(row) {
|
||||
if (!row) return undefined
|
||||
return {
|
||||
value: row.id,
|
||||
label: row.name,
|
||||
pvalue: row.pid,
|
||||
level: row.level,
|
||||
hasChildren: !!row.has_children,
|
||||
}
|
||||
}
|
||||
|
||||
function buildProvinceIndexList() {
|
||||
return (addressOption).map((province) => {
|
||||
const children = (province)
|
||||
.children ?? [];
|
||||
return {
|
||||
province: {
|
||||
value: province.value,
|
||||
label: province.label,
|
||||
pvalue: province.pvalue,
|
||||
},
|
||||
children: children.map((c) => ({
|
||||
value: c.value,
|
||||
label: c.label,
|
||||
pvalue: c.pvalue,
|
||||
})),
|
||||
isMunicipality: detectMunicipality(province, children),
|
||||
};
|
||||
});
|
||||
/** 组装对外 address 值 [provinceId, leafId] */
|
||||
export function buildAddressOutput(provinceId, cityId, districtId) {
|
||||
if (!provinceId) return undefined
|
||||
const leafId = districtId != null ? districtId : cityId
|
||||
if (!leafId) return undefined
|
||||
return [provinceId, leafId]
|
||||
}
|
||||
|
||||
function getProvinceIndexList() {
|
||||
if (!provinceIndexCache) {
|
||||
provinceIndexCache = buildProvinceIndexList();
|
||||
}
|
||||
return provinceIndexCache;
|
||||
/**
|
||||
* 同步解析:只读本地缓存(由 ensureResolvedAddress 填充)
|
||||
* 为什么:部分展示位是同步的,不能直接 await
|
||||
*/
|
||||
export function resolveAddressValue(value) {
|
||||
if (!value || value.length < 2) return {}
|
||||
const provinceId = value[0]
|
||||
const leafId = value[1]
|
||||
return (
|
||||
pairCache.get(cacheKey(provinceId, leafId)) || {
|
||||
provinceId,
|
||||
cityId: leafId,
|
||||
}
|
||||
)
|
||||
}
|
||||
|
||||
function findProvinceIndex(provinceId) {
|
||||
if (!provinceId) {
|
||||
return undefined;
|
||||
}
|
||||
return getProvinceIndexList().find((p) => p.province.value === provinceId);
|
||||
/**
|
||||
* 异步解析并写入缓存(含软删节点,后端 resolve 不过滤 deleted_at)
|
||||
*/
|
||||
export async function ensureResolvedAddress(value) {
|
||||
if (!value || value.length < 2) return {}
|
||||
const provinceId = value[0]
|
||||
const leafId = value[1]
|
||||
const key = cacheKey(provinceId, leafId)
|
||||
if (pairCache.has(key)) {
|
||||
return pairCache.get(key)
|
||||
}
|
||||
try {
|
||||
const res = await resolveRegionPair(provinceId, leafId)
|
||||
const { ok, payload } = unwrapXkApi(res)
|
||||
if (!ok || !payload) {
|
||||
return { provinceId, cityId: leafId }
|
||||
}
|
||||
const resolved = {
|
||||
provinceId,
|
||||
cityId: undefined,
|
||||
districtId: undefined,
|
||||
province: payload.province ? toNode(payload.province) : undefined,
|
||||
city: payload.city
|
||||
? {
|
||||
value: payload.city.id,
|
||||
label: payload.city.name,
|
||||
pvalue: payload.city.pid,
|
||||
level: payload.city.level,
|
||||
}
|
||||
: undefined,
|
||||
district: payload.district
|
||||
? {
|
||||
value: payload.district.id,
|
||||
label: payload.district.name,
|
||||
pvalue: payload.district.pid,
|
||||
level: payload.district.level,
|
||||
}
|
||||
: undefined,
|
||||
pathLabel: payload.path_label || '',
|
||||
}
|
||||
if (payload.district && !payload.city) {
|
||||
resolved.districtId = leafId
|
||||
} else if (payload.district) {
|
||||
resolved.cityId = payload.city && payload.city.id
|
||||
resolved.districtId = payload.district.id
|
||||
} else {
|
||||
resolved.cityId = leafId
|
||||
}
|
||||
pairCache.set(key, resolved)
|
||||
if (resolved.pathLabel) {
|
||||
displayCache.set(key, resolved.pathLabel)
|
||||
}
|
||||
return resolved
|
||||
} catch (e) {
|
||||
return { provinceId, cityId: leafId }
|
||||
}
|
||||
}
|
||||
|
||||
function findChild(
|
||||
provinceIndex,
|
||||
childId,
|
||||
) {
|
||||
if (!childId) {
|
||||
return undefined;
|
||||
}
|
||||
return provinceIndex.children.find((c) => c.value === childId);
|
||||
}
|
||||
|
||||
function getCityNamePrefix(label) {
|
||||
return label.replace(/市$/, '');
|
||||
}
|
||||
|
||||
/** 省级列表 */
|
||||
export function getProvinces() {
|
||||
return getProvinceIndexList().map((p) => p.province);
|
||||
}
|
||||
|
||||
/** 市级列表(直辖市返回空) */
|
||||
export function getCities(provinceId) {
|
||||
const index = findProvinceIndex(provinceId);
|
||||
if (!index || index.isMunicipality) {
|
||||
return [];
|
||||
}
|
||||
return index.children;
|
||||
}
|
||||
|
||||
/** 区级列表 */
|
||||
export function getDistricts(
|
||||
provinceId,
|
||||
cityId,
|
||||
) {
|
||||
const index = findProvinceIndex(provinceId);
|
||||
if (!index) {
|
||||
return [];
|
||||
}
|
||||
if (index.isMunicipality) {
|
||||
return index.children;
|
||||
}
|
||||
if (!cityId) {
|
||||
return [];
|
||||
}
|
||||
const city = findChild(index, cityId);
|
||||
if (!city || !isPrefectureCityLabel(city.label)) {
|
||||
return [];
|
||||
}
|
||||
const prefix = getCityNamePrefix(city.label);
|
||||
return index.children.filter(
|
||||
(c) =>
|
||||
c.value !== cityId &&
|
||||
!isPrefectureCityLabel(c.label) &&
|
||||
c.label.startsWith(prefix),
|
||||
);
|
||||
}
|
||||
|
||||
/** 当前层级候选列表 */
|
||||
export function getLevelOptions(
|
||||
level,
|
||||
ctx,
|
||||
) {
|
||||
if (level === 'province') {
|
||||
return getProvinces();
|
||||
}
|
||||
if (level === 'city') {
|
||||
return getCities(ctx.provinceId);
|
||||
}
|
||||
return getDistricts(ctx.provinceId, ctx.cityId);
|
||||
}
|
||||
|
||||
/** 选择某级后的下一层级(无则 undefined) */
|
||||
export function getNextLevel(
|
||||
currentLevel,
|
||||
ctx,
|
||||
) {
|
||||
const index = findProvinceIndex(ctx.provinceId);
|
||||
if (!index) {
|
||||
return undefined;
|
||||
}
|
||||
if (currentLevel === 'province') {
|
||||
return index.isMunicipality ? 'district' : 'city';
|
||||
}
|
||||
if (currentLevel === 'city') {
|
||||
if (!ctx.cityId) {
|
||||
return undefined;
|
||||
}
|
||||
const districts = getDistricts(ctx.provinceId, ctx.cityId);
|
||||
return districts.length > 0 ? 'district' : undefined;
|
||||
}
|
||||
return undefined;
|
||||
}
|
||||
|
||||
/** 当前层级选中后是否可直接完成(叶节点) */
|
||||
export function canCompleteAfterSelect(
|
||||
level,
|
||||
ctx,
|
||||
item,
|
||||
) {
|
||||
const index = findProvinceIndex(ctx.provinceId);
|
||||
if (!index) {
|
||||
return false;
|
||||
}
|
||||
if (level === 'district') {
|
||||
return true;
|
||||
}
|
||||
if (level === 'city') {
|
||||
if (index.isMunicipality) {
|
||||
return false;
|
||||
}
|
||||
if (!isPrefectureCityLabel(item.label)) {
|
||||
return true;
|
||||
}
|
||||
return getDistricts(ctx.provinceId, item.value).length === 0;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
/** 组装对外 address 值 */
|
||||
export function buildAddressOutput(
|
||||
provinceId,
|
||||
cityId,
|
||||
districtId,
|
||||
) {
|
||||
if (!provinceId) {
|
||||
return undefined;
|
||||
}
|
||||
const leafId = districtId ?? cityId;
|
||||
if (!leafId) {
|
||||
return undefined;
|
||||
}
|
||||
return [provinceId, leafId];
|
||||
}
|
||||
|
||||
/** 由 address 反查省/市/区 */
|
||||
export function resolveAddressValue(
|
||||
value,
|
||||
) {
|
||||
if (!value || value.length < 2) {
|
||||
return {};
|
||||
}
|
||||
const [provinceId, leafId] = value;
|
||||
const index = findProvinceIndex(provinceId);
|
||||
if (!index) {
|
||||
return { provinceId };
|
||||
}
|
||||
const leaf = findChild(index, leafId);
|
||||
if (!leaf) {
|
||||
return { provinceId, province: index.province };
|
||||
}
|
||||
|
||||
if (index.isMunicipality) {
|
||||
return {
|
||||
provinceId,
|
||||
districtId: leafId,
|
||||
province: index.province,
|
||||
district: leaf,
|
||||
};
|
||||
}
|
||||
|
||||
const isLeafDistrict =
|
||||
!isPrefectureCityLabel(leaf.label) && isDistrictLikeLabel(leaf.label);
|
||||
|
||||
if (isPrefectureCityLabel(leaf.label)) {
|
||||
return {
|
||||
provinceId,
|
||||
cityId: leafId,
|
||||
province: index.province,
|
||||
city: leaf,
|
||||
};
|
||||
}
|
||||
|
||||
if (isLeafDistrict) {
|
||||
for (const city of index.children.filter((c) =>
|
||||
isPrefectureCityLabel(c.label),
|
||||
)) {
|
||||
const prefix = getCityNamePrefix(city.label);
|
||||
if (leaf.label.startsWith(prefix)) {
|
||||
return {
|
||||
provinceId,
|
||||
cityId: city.value,
|
||||
districtId: leafId,
|
||||
province: index.province,
|
||||
city,
|
||||
district: leaf,
|
||||
};
|
||||
}
|
||||
}
|
||||
return {
|
||||
provinceId,
|
||||
cityId: leafId,
|
||||
province: index.province,
|
||||
city: leaf,
|
||||
};
|
||||
}
|
||||
|
||||
return {
|
||||
provinceId,
|
||||
cityId: leafId,
|
||||
province: index.province,
|
||||
city: leaf,
|
||||
};
|
||||
}
|
||||
|
||||
/** 面包屑展示项 */
|
||||
export function formatBreadcrumbItems(
|
||||
resolved,
|
||||
) {
|
||||
const items = [];
|
||||
if (resolved.provinceId && resolved.province) {
|
||||
items.push({
|
||||
level: 'province',
|
||||
id: resolved.provinceId,
|
||||
label: resolved.province.label,
|
||||
});
|
||||
}
|
||||
const index = findProvinceIndex(resolved.provinceId);
|
||||
if (index?.isMunicipality) {
|
||||
if (resolved.districtId && resolved.district) {
|
||||
items.push({
|
||||
level: 'district',
|
||||
id: resolved.districtId,
|
||||
label: resolved.district.label,
|
||||
});
|
||||
}
|
||||
return items;
|
||||
}
|
||||
if (resolved.cityId && resolved.city) {
|
||||
items.push({
|
||||
level: 'city',
|
||||
id: resolved.cityId,
|
||||
label: resolved.city.label,
|
||||
});
|
||||
}
|
||||
if (resolved.districtId && resolved.district) {
|
||||
items.push({
|
||||
level: 'district',
|
||||
id: resolved.districtId,
|
||||
label: resolved.district.label,
|
||||
});
|
||||
}
|
||||
return items;
|
||||
}
|
||||
|
||||
/** 触发器展示文案 */
|
||||
/** 同步展示:优先缓存;未命中触发异步并先返回空串 */
|
||||
export function formatAddressDisplay(value) {
|
||||
const items = formatBreadcrumbItems(resolveAddressValue(value));
|
||||
return items.map((i) => i.label).join(' / ');
|
||||
if (!value || value.length < 2) return ''
|
||||
const key = cacheKey(value[0], value[1])
|
||||
if (displayCache.has(key)) {
|
||||
return displayCache.get(key)
|
||||
}
|
||||
ensureResolvedAddress(value)
|
||||
return ''
|
||||
}
|
||||
|
||||
/** 当前层级搜索占位 */
|
||||
export function getLevelSearchPlaceholder(level) {
|
||||
const map = {
|
||||
province: '搜索省',
|
||||
city: '搜索市/县',
|
||||
district: '搜索区',
|
||||
};
|
||||
return map[level];
|
||||
export function formatBreadcrumbItems(resolved) {
|
||||
const items = []
|
||||
if (resolved.province) {
|
||||
items.push({
|
||||
level: 'province',
|
||||
id: resolved.province.value,
|
||||
label: resolved.province.label,
|
||||
})
|
||||
}
|
||||
if (resolved.city) {
|
||||
items.push({
|
||||
level: 'city',
|
||||
id: resolved.city.value,
|
||||
label: resolved.city.label,
|
||||
})
|
||||
}
|
||||
if (resolved.district) {
|
||||
items.push({
|
||||
level: 'district',
|
||||
id: resolved.district.value,
|
||||
label: resolved.district.label,
|
||||
})
|
||||
}
|
||||
return items
|
||||
}
|
||||
|
||||
/** 模糊筛选 */
|
||||
export function filterAddressOptions(
|
||||
options,
|
||||
keyword,
|
||||
) {
|
||||
const q = keyword.trim().toLowerCase();
|
||||
if (!q) {
|
||||
return options;
|
||||
}
|
||||
return options.filter((o) => o.label.toLowerCase().includes(q));
|
||||
export function buildBreadcrumbFromContext(ctx, labels) {
|
||||
const items = []
|
||||
const lab = labels || {}
|
||||
if (ctx.provinceId) {
|
||||
items.push({
|
||||
level: 'province',
|
||||
id: ctx.provinceId,
|
||||
label: lab.province || String(ctx.provinceId),
|
||||
})
|
||||
}
|
||||
if (ctx.cityId) {
|
||||
items.push({
|
||||
level: 'city',
|
||||
id: ctx.cityId,
|
||||
label: lab.city || String(ctx.cityId),
|
||||
})
|
||||
}
|
||||
if (ctx.districtId) {
|
||||
items.push({
|
||||
level: 'district',
|
||||
id: ctx.districtId,
|
||||
label: lab.district || String(ctx.districtId),
|
||||
})
|
||||
}
|
||||
return items
|
||||
}
|
||||
|
||||
/** 从已选上下文生成面包屑(面板内) */
|
||||
export function buildBreadcrumbFromContext(
|
||||
ctx,
|
||||
) {
|
||||
return formatBreadcrumbItems({
|
||||
provinceId: ctx.provinceId,
|
||||
cityId: ctx.cityId,
|
||||
districtId: ctx.districtId,
|
||||
province: findProvinceIndex(ctx.provinceId)?.province,
|
||||
city: findChild(findProvinceIndex(ctx.provinceId), ctx.cityId),
|
||||
district: findChild(findProvinceIndex(ctx.provinceId), ctx.districtId),
|
||||
});
|
||||
/** 拉取某一层选项 */
|
||||
export async function fetchLevelOptions(level, ctx) {
|
||||
let pid = 0
|
||||
if (level === 'city') pid = ctx.provinceId || 0
|
||||
else if (level === 'district') pid = ctx.cityId || 0
|
||||
const res = await getRegionChildren(pid)
|
||||
const { ok, payload } = unwrapXkApi(res)
|
||||
const rows = ok && Array.isArray(payload) ? payload : []
|
||||
return rows.map((r) => toNode(r))
|
||||
}
|
||||
|
||||
/** 根据面板内选中生成 ResolvedAddress */
|
||||
export function contextToResolved(ctx) {
|
||||
const index = findProvinceIndex(ctx.provinceId);
|
||||
return {
|
||||
provinceId: ctx.provinceId,
|
||||
cityId: ctx.cityId,
|
||||
districtId: ctx.districtId,
|
||||
province: index?.province,
|
||||
city: index ? findChild(index, ctx.cityId) : undefined,
|
||||
district: index ? findChild(index, ctx.districtId) : undefined,
|
||||
};
|
||||
export function levelOptionsToRows(level, options) {
|
||||
return (options || []).map((node) => ({
|
||||
level,
|
||||
node,
|
||||
label: node.label,
|
||||
complete: !node.hasChildren,
|
||||
}))
|
||||
}
|
||||
|
||||
/** 是否直辖市 */
|
||||
export function isMunicipalityProvince(provinceId) {
|
||||
return !!findProvinceIndex(provinceId)?.isMunicipality;
|
||||
export async function searchAddressHits(keyword) {
|
||||
const kw = (keyword || '').trim()
|
||||
if (!kw) return []
|
||||
const res = await searchRegions(kw, 30)
|
||||
const { ok, payload } = unwrapXkApi(res)
|
||||
const hits = ok && Array.isArray(payload) ? payload : []
|
||||
return hits.map((h) => ({
|
||||
level: levelFromNumber(h.level),
|
||||
node: toNode(h),
|
||||
pathLabel: h.path_label || h.name,
|
||||
complete: !!h.complete,
|
||||
path: h.path,
|
||||
}))
|
||||
}
|
||||
|
||||
/** 打开面板时的初始层级(有回填则进入待选级,否则省) */
|
||||
export function getInitialPickerLevel(
|
||||
resolved,
|
||||
) {
|
||||
const index = findProvinceIndex(resolved.provinceId);
|
||||
if (!resolved.provinceId || !index) {
|
||||
return 'province';
|
||||
}
|
||||
if (index.isMunicipality) {
|
||||
return 'district';
|
||||
}
|
||||
if (!resolved.cityId) {
|
||||
return 'city';
|
||||
}
|
||||
const districts = getDistricts(resolved.provinceId, resolved.cityId);
|
||||
if (!resolved.districtId && districts.length > 0) {
|
||||
return 'district';
|
||||
}
|
||||
return 'city';
|
||||
}
|
||||
|
||||
/** 当前级候选转列表行 */
|
||||
export function levelOptionsToRows(
|
||||
level,
|
||||
ctx,
|
||||
) {
|
||||
return getLevelOptions(level, ctx).map((node) => ({
|
||||
level,
|
||||
node,
|
||||
label: node.label,
|
||||
complete: canCompleteAfterSelect(
|
||||
level,
|
||||
level === 'city'
|
||||
? { provinceId: ctx.provinceId, cityId: node.value }
|
||||
: level === 'district'
|
||||
? {
|
||||
provinceId: ctx.provinceId,
|
||||
cityId: ctx.cityId,
|
||||
districtId: node.value,
|
||||
}
|
||||
: ctx,
|
||||
node,
|
||||
),
|
||||
}));
|
||||
}
|
||||
|
||||
/** 跨级模糊搜索(含第三级区/县) */
|
||||
export function searchAddressHits(
|
||||
keyword,
|
||||
ctx,
|
||||
) {
|
||||
const q = keyword.trim().toLowerCase();
|
||||
if (!q) {
|
||||
return [];
|
||||
}
|
||||
|
||||
const hits = [];
|
||||
const seen = new Set();
|
||||
|
||||
const push = (hit) => {
|
||||
const key = `${hit.level}-${hit.node.value}`;
|
||||
if (!seen.has(key)) {
|
||||
seen.add(key);
|
||||
hits.push(hit);
|
||||
}
|
||||
};
|
||||
|
||||
if (!ctx.provinceId) {
|
||||
for (const p of getProvinces()) {
|
||||
if (p.label.toLowerCase().includes(q)) {
|
||||
push({
|
||||
level: 'province',
|
||||
node: p,
|
||||
pathLabel: p.label,
|
||||
complete: false,
|
||||
});
|
||||
}
|
||||
}
|
||||
return hits;
|
||||
}
|
||||
|
||||
const index = findProvinceIndex(ctx.provinceId);
|
||||
if (!index) {
|
||||
return hits;
|
||||
}
|
||||
|
||||
if (index.isMunicipality) {
|
||||
for (const d of index.children) {
|
||||
if (d.label.toLowerCase().includes(q)) {
|
||||
push({
|
||||
level: 'district',
|
||||
node: d,
|
||||
pathLabel: `${index.province.label} / ${d.label}`,
|
||||
complete: true,
|
||||
});
|
||||
}
|
||||
}
|
||||
return hits;
|
||||
}
|
||||
|
||||
const cityNode = ctx.cityId ? findChild(index, ctx.cityId) : undefined;
|
||||
|
||||
if (!ctx.cityId) {
|
||||
for (const child of index.children) {
|
||||
if (!child.label.toLowerCase().includes(q)) {
|
||||
continue;
|
||||
}
|
||||
const rowCtx = { provinceId: ctx.provinceId, cityId: child.value };
|
||||
push({
|
||||
level: 'city',
|
||||
node: child,
|
||||
pathLabel: `${index.province.label} / ${child.label}`,
|
||||
complete: canCompleteAfterSelect('city', rowCtx, child),
|
||||
});
|
||||
}
|
||||
for (const child of index.children.filter((c) => isPrefectureCityLabel(c.label))) {
|
||||
for (const d of getDistricts(ctx.provinceId, child.value)) {
|
||||
if (!d.label.toLowerCase().includes(q)) {
|
||||
continue;
|
||||
}
|
||||
push({
|
||||
level: 'district',
|
||||
node: d,
|
||||
pathLabel: `${index.province.label} / ${child.label} / ${d.label}`,
|
||||
complete: true,
|
||||
});
|
||||
}
|
||||
}
|
||||
return hits;
|
||||
}
|
||||
|
||||
if (cityNode && cityNode.label.toLowerCase().includes(q)) {
|
||||
push({
|
||||
level: 'city',
|
||||
node: cityNode,
|
||||
pathLabel: `${index.province.label} / ${cityNode.label}`,
|
||||
complete: canCompleteAfterSelect('city', ctx, cityNode),
|
||||
});
|
||||
}
|
||||
|
||||
for (const d of getDistricts(ctx.provinceId, ctx.cityId)) {
|
||||
if (d.label.toLowerCase().includes(q)) {
|
||||
push({
|
||||
level: 'district',
|
||||
node: d,
|
||||
pathLabel: `${index.province.label} / ${cityNode?.label ?? ''} / ${d.label}`,
|
||||
complete: true,
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
return hits;
|
||||
}
|
||||
|
||||
/** 搜索命中转列表行 */
|
||||
export function searchHitsToRows(hits) {
|
||||
return hits.map((hit) => ({
|
||||
level: hit.level,
|
||||
node: hit.node,
|
||||
label: hit.pathLabel,
|
||||
complete: hit.complete,
|
||||
}));
|
||||
return (hits || []).map((hit) => ({
|
||||
level: hit.level,
|
||||
node: hit.node,
|
||||
label: hit.pathLabel,
|
||||
complete: hit.complete,
|
||||
}))
|
||||
}
|
||||
|
||||
/** 应用跨级搜索选中 */
|
||||
export function applySearchHit(
|
||||
hit,
|
||||
ctx,
|
||||
) {
|
||||
if (hit.level === 'province') {
|
||||
return {
|
||||
provinceId: hit.node.value,
|
||||
cityId: undefined,
|
||||
districtId: undefined,
|
||||
};
|
||||
}
|
||||
if (hit.level === 'city') {
|
||||
return {
|
||||
provinceId: ctx.provinceId,
|
||||
cityId: hit.node.value,
|
||||
districtId: undefined,
|
||||
};
|
||||
}
|
||||
if (hit.level === 'district' && findProvinceIndex(ctx.provinceId)?.isMunicipality) {
|
||||
return {
|
||||
provinceId: ctx.provinceId,
|
||||
cityId: undefined,
|
||||
districtId: hit.node.value,
|
||||
};
|
||||
}
|
||||
return {
|
||||
provinceId: ctx.provinceId,
|
||||
cityId: ctx.cityId,
|
||||
districtId: hit.node.value,
|
||||
};
|
||||
export function applySearchHit(hit) {
|
||||
const next = {}
|
||||
const path = hit.path || []
|
||||
for (let i = 0; i < path.length; i++) {
|
||||
const node = path[i]
|
||||
if (node.level === 1) next.provinceId = node.id
|
||||
else if (node.level === 2) next.cityId = node.id
|
||||
else if (node.level === 3) next.districtId = node.id
|
||||
}
|
||||
if (hit.level === 'province') {
|
||||
next.provinceId = hit.node.value
|
||||
} else if (hit.level === 'city') {
|
||||
next.cityId = hit.node.value
|
||||
if (!next.provinceId) next.provinceId = hit.node.pvalue
|
||||
} else {
|
||||
next.districtId = hit.node.value
|
||||
if (!next.cityId) next.cityId = hit.node.pvalue
|
||||
}
|
||||
return next
|
||||
}
|
||||
|
||||
/** 高亮项是否有下一级 */
|
||||
export function rowHasNextLevel(
|
||||
row,
|
||||
ctx,
|
||||
) {
|
||||
if (row.level === 'province') {
|
||||
return !!getNextLevel('province', {
|
||||
provinceId: row.node.value,
|
||||
cityId: undefined,
|
||||
districtId: undefined,
|
||||
});
|
||||
}
|
||||
if (row.level === 'city') {
|
||||
return !!getNextLevel('city', {
|
||||
provinceId: ctx.provinceId,
|
||||
cityId: row.node.value,
|
||||
districtId: undefined,
|
||||
});
|
||||
}
|
||||
return false;
|
||||
export function getNextLevel(level, _ctx, hasChildren) {
|
||||
if (hasChildren === false) return undefined
|
||||
if (level === 'province') return 'city'
|
||||
if (level === 'city') return 'district'
|
||||
return undefined
|
||||
}
|
||||
|
||||
/** 点击面包屑项后截断选中并返回新上下文 */
|
||||
export function truncateContextToBreadcrumb(
|
||||
ctx,
|
||||
item,
|
||||
) {
|
||||
if (item.level === 'province') {
|
||||
return {
|
||||
provinceId: item.id,
|
||||
cityId: undefined,
|
||||
districtId: undefined,
|
||||
};
|
||||
}
|
||||
if (item.level === 'city') {
|
||||
return {
|
||||
provinceId: ctx.provinceId,
|
||||
cityId: item.id,
|
||||
districtId: undefined,
|
||||
};
|
||||
}
|
||||
return {
|
||||
provinceId: ctx.provinceId,
|
||||
cityId: ctx.cityId,
|
||||
districtId: item.id,
|
||||
};
|
||||
export function getInitialPickerLevel(resolved) {
|
||||
if (resolved.districtId) return 'district'
|
||||
if (resolved.cityId) return 'city'
|
||||
return 'province'
|
||||
}
|
||||
|
||||
export function canCompleteAfterSelect(level, _ctx, item) {
|
||||
if (level === 'district') return true
|
||||
return !item.hasChildren
|
||||
}
|
||||
|
||||
export function rowHasNextLevel(row) {
|
||||
return !row.complete && !!(row.node && row.node.hasChildren)
|
||||
}
|
||||
|
||||
export function truncateContextToBreadcrumb(ctx, item) {
|
||||
if (item.level === 'province') {
|
||||
return { provinceId: item.id }
|
||||
}
|
||||
if (item.level === 'city') {
|
||||
return { provinceId: ctx.provinceId, cityId: item.id }
|
||||
}
|
||||
return {
|
||||
provinceId: ctx.provinceId,
|
||||
cityId: ctx.cityId,
|
||||
districtId: item.id,
|
||||
}
|
||||
}
|
||||
|
||||
export function getLevelSearchPlaceholder(level) {
|
||||
if (level === 'province') return '搜索省(地名/首拼/全拼)'
|
||||
if (level === 'city') return '搜索市(地名/首拼/全拼)'
|
||||
return '搜索区县(地名/首拼/全拼)'
|
||||
}
|
||||
|
||||
/** 兼容旧调用:直辖市由 hasChildren 驱动,保留空实现 */
|
||||
export function isMunicipalityProvince() {
|
||||
return false
|
||||
}
|
||||
|
||||
File diff suppressed because one or more lines are too long
@@ -132,7 +132,7 @@
|
||||
<view
|
||||
class="_name"
|
||||
v-for="(ex, exIdx) in resolveExcipients(item)"
|
||||
:key="ex.drug_id || exIdx"
|
||||
:key="exIdx"
|
||||
>
|
||||
<view class="text">
|
||||
<text>{{ ex.display_name }}</text>
|
||||
|
||||
@@ -8,7 +8,7 @@
|
||||
<drawer-page-container v-model="show" title="选择省市区">
|
||||
<view class="drawer-body" :style="drawerBodyStyle">
|
||||
<view class="search-box">
|
||||
<u-input v-model="keyword" placeholder="搜索省/市/区" clearable :adjust-position="false" />
|
||||
<u-input v-model="keyword" placeholder="地名/首拼/全拼" clearable :adjust-position="false" />
|
||||
</view>
|
||||
<scroll-view scroll-x class="crumb-scroll">
|
||||
<view class="crumbs">
|
||||
@@ -22,6 +22,7 @@
|
||||
</view>
|
||||
</scroll-view>
|
||||
<scroll-view scroll-y class="list-scroll" :style="listScrollStyle">
|
||||
<view v-if="loading" class="empty">加载中...</view>
|
||||
<view
|
||||
v-for="row in listRows"
|
||||
:key="row.rowKey"
|
||||
@@ -31,7 +32,7 @@
|
||||
<text class="row-label">{{ isSearching ? row.label : row.node.label }}</text>
|
||||
<text v-if="!isSearching && row.showArrow" class="row-arrow">›</text>
|
||||
</view>
|
||||
<view v-if="!listRows.length" class="empty">无匹配结果</view>
|
||||
<view v-if="!loading && !listRows.length" class="empty">无匹配结果</view>
|
||||
</scroll-view>
|
||||
</view>
|
||||
</drawer-page-container>
|
||||
@@ -39,21 +40,26 @@
|
||||
</template>
|
||||
|
||||
<script>
|
||||
/**
|
||||
* 省市区选择器:直连 region-picker(懒加载 + 合一搜索)
|
||||
* 对外仍 emit [provinceId, leafId]
|
||||
*/
|
||||
import DrawerPageContainer from '@/subPackages/sub_salesperson/components/DrawerPageContainer.vue'
|
||||
import {
|
||||
formatAddressDisplay,
|
||||
resolveAddressValue,
|
||||
applySearchHit,
|
||||
buildAddressOutput,
|
||||
buildBreadcrumbFromContext,
|
||||
canCompleteAfterSelect,
|
||||
ensureResolvedAddress,
|
||||
fetchLevelOptions,
|
||||
formatAddressDisplay,
|
||||
getInitialPickerLevel,
|
||||
getNextLevel,
|
||||
levelOptionsToRows,
|
||||
rowHasNextLevel,
|
||||
searchAddressHits,
|
||||
searchHitsToRows,
|
||||
applySearchHit,
|
||||
rowHasNextLevel,
|
||||
truncateContextToBreadcrumb,
|
||||
getNextLevel,
|
||||
canCompleteAfterSelect,
|
||||
} from '@/subPackages/sub_clinic_salesperson/utils/address-index.js'
|
||||
|
||||
export default {
|
||||
@@ -66,36 +72,32 @@ export default {
|
||||
data() {
|
||||
return {
|
||||
show: false,
|
||||
loading: false,
|
||||
keyword: '',
|
||||
currentLevel: 'province',
|
||||
ctx: { provinceId: undefined, cityId: undefined, districtId: undefined },
|
||||
crumbLabels: {},
|
||||
listRows: [],
|
||||
keyboardHeight: 0,
|
||||
_searchTimer: null,
|
||||
_displayTick: 0,
|
||||
}
|
||||
},
|
||||
computed: {
|
||||
// 依赖 _displayTick:异步 resolve 写缓存后强制刷新展示文案
|
||||
displayText() {
|
||||
void this._displayTick
|
||||
return formatAddressDisplay(this.value)
|
||||
},
|
||||
isSearching() {
|
||||
return !!(this.keyword || '').trim()
|
||||
},
|
||||
breadcrumbs() {
|
||||
return buildBreadcrumbFromContext(this.ctx).map((item) => ({
|
||||
return buildBreadcrumbFromContext(this.ctx, this.crumbLabels).map((item) => ({
|
||||
...item,
|
||||
rowKey: item.level + '-' + item.id,
|
||||
}))
|
||||
},
|
||||
listRows() {
|
||||
const rows = this.isSearching
|
||||
? searchHitsToRows(searchAddressHits(this.keyword, this.ctx))
|
||||
: levelOptionsToRows(this.currentLevel, this.ctx)
|
||||
// 箭头在脚本里算好,模板禁止方法调用绑定(部分机型 WXML 会点不动/编译异常)
|
||||
return rows.map((row) => ({
|
||||
...row,
|
||||
rowKey: row.level + '-' + row.node.value,
|
||||
showArrow: !this.isSearching && rowHasNextLevel(row, this.ctx),
|
||||
}))
|
||||
},
|
||||
drawerBodyStyle() {
|
||||
if (!this.keyboardHeight) {
|
||||
return {}
|
||||
@@ -124,8 +126,25 @@ export default {
|
||||
this.keyboardHeight = 0
|
||||
this.unbindKeyboardListener()
|
||||
},
|
||||
keyword() {
|
||||
if (!this.show) return
|
||||
clearTimeout(this._searchTimer)
|
||||
this._searchTimer = setTimeout(() => {
|
||||
this.reloadList()
|
||||
}, 250)
|
||||
},
|
||||
value: {
|
||||
deep: true,
|
||||
immediate: true,
|
||||
handler(val) {
|
||||
if (!this.show) {
|
||||
this.prefetchDisplay(val)
|
||||
}
|
||||
},
|
||||
},
|
||||
},
|
||||
beforeDestroy() {
|
||||
clearTimeout(this._searchTimer)
|
||||
this.unbindKeyboardListener()
|
||||
},
|
||||
methods: {
|
||||
@@ -145,69 +164,144 @@ export default {
|
||||
this._keyboardBound = false
|
||||
this._keyboardHandler = null
|
||||
},
|
||||
syncFromValue() {
|
||||
const resolved = resolveAddressValue(this.value)
|
||||
async prefetchDisplay(val) {
|
||||
await ensureResolvedAddress(val)
|
||||
this._displayTick += 1
|
||||
},
|
||||
async syncFromValue() {
|
||||
const resolved = await ensureResolvedAddress(this.value)
|
||||
this.ctx = {
|
||||
provinceId: resolved.provinceId,
|
||||
cityId: resolved.cityId,
|
||||
districtId: resolved.districtId,
|
||||
}
|
||||
this.currentLevel = getInitialPickerLevel(resolved)
|
||||
this.crumbLabels = {
|
||||
province: resolved.province && resolved.province.label,
|
||||
city: resolved.city && resolved.city.label,
|
||||
district: resolved.district && resolved.district.label,
|
||||
}
|
||||
if (resolved.districtId && resolved.cityId) {
|
||||
this.currentLevel = 'district'
|
||||
} else if (resolved.cityId && resolved.provinceId) {
|
||||
this.currentLevel = resolved.district ? 'district' : 'city'
|
||||
} else {
|
||||
this.currentLevel = getInitialPickerLevel(resolved)
|
||||
}
|
||||
this.keyword = ''
|
||||
this._displayTick += 1
|
||||
},
|
||||
openDrawer() {
|
||||
this.syncFromValue()
|
||||
async reloadList() {
|
||||
this.loading = true
|
||||
try {
|
||||
if (this.isSearching) {
|
||||
const hits = await searchAddressHits(this.keyword)
|
||||
this.listRows = searchHitsToRows(hits).map((row) => ({
|
||||
...row,
|
||||
rowKey: row.level + '-' + row.node.value,
|
||||
showArrow: false,
|
||||
}))
|
||||
} else {
|
||||
const options = await fetchLevelOptions(this.currentLevel, this.ctx)
|
||||
this.listRows = levelOptionsToRows(this.currentLevel, options).map((row) => ({
|
||||
...row,
|
||||
rowKey: row.level + '-' + row.node.value,
|
||||
showArrow: rowHasNextLevel(row),
|
||||
}))
|
||||
}
|
||||
} finally {
|
||||
this.loading = false
|
||||
}
|
||||
},
|
||||
async openDrawer() {
|
||||
await this.syncFromValue()
|
||||
this.show = true
|
||||
await this.reloadList()
|
||||
},
|
||||
emitValue() {
|
||||
async emitValue() {
|
||||
const out = buildAddressOutput(this.ctx.provinceId, this.ctx.cityId, this.ctx.districtId)
|
||||
if (out) this.$emit('change', out)
|
||||
if (out) {
|
||||
await ensureResolvedAddress(out)
|
||||
this._displayTick += 1
|
||||
this.$emit('change', out)
|
||||
this.$emit('input', out)
|
||||
}
|
||||
},
|
||||
onCrumb(item) {
|
||||
async onCrumb(item) {
|
||||
this.ctx = truncateContextToBreadcrumb(this.ctx, item)
|
||||
this.currentLevel = item.level
|
||||
if (item.level === 'province') {
|
||||
this.currentLevel = 'city'
|
||||
this.crumbLabels = { province: item.label }
|
||||
} else if (item.level === 'city') {
|
||||
this.currentLevel = 'district'
|
||||
this.crumbLabels = {
|
||||
province: this.crumbLabels.province,
|
||||
city: item.label,
|
||||
}
|
||||
} else {
|
||||
this.currentLevel = 'district'
|
||||
}
|
||||
this.keyword = ''
|
||||
await this.reloadList()
|
||||
},
|
||||
onPickRow(row) {
|
||||
async onPickRow(row) {
|
||||
if (this.isSearching) {
|
||||
const hit = searchAddressHits(this.keyword, this.ctx).find(
|
||||
const hits = await searchAddressHits(this.keyword)
|
||||
const hit = hits.find(
|
||||
(h) => h.level === row.level && h.node.value === row.node.value
|
||||
)
|
||||
if (!hit) return
|
||||
this.ctx = applySearchHit(hit, this.ctx)
|
||||
this.ctx = applySearchHit(hit)
|
||||
const parts = (hit.pathLabel || '').split('/').filter(Boolean)
|
||||
this.crumbLabels = {
|
||||
province: parts[0],
|
||||
city: parts[1],
|
||||
district: parts[2],
|
||||
}
|
||||
if (hit.complete) {
|
||||
this.emitValue()
|
||||
await this.emitValue()
|
||||
this.show = false
|
||||
return
|
||||
}
|
||||
const next = getNextLevel(hit.level, this.ctx)
|
||||
const next = getNextLevel(hit.level, this.ctx, !hit.complete)
|
||||
this.currentLevel = next || hit.level
|
||||
this.keyword = ''
|
||||
await this.reloadList()
|
||||
return
|
||||
}
|
||||
|
||||
const pickCtx = row.level === 'city'
|
||||
? { provinceId: this.ctx.provinceId, cityId: row.node.value }
|
||||
: row.level === 'district'
|
||||
? { provinceId: this.ctx.provinceId, cityId: this.ctx.cityId, districtId: row.node.value }
|
||||
: { provinceId: row.node.value, cityId: undefined, districtId: undefined }
|
||||
|
||||
if (row.level === 'province') {
|
||||
this.ctx = { provinceId: row.node.value, cityId: undefined, districtId: undefined }
|
||||
this.currentLevel = getNextLevel('province', this.ctx) || 'province'
|
||||
} else if (row.level === 'city') {
|
||||
this.ctx = { ...this.ctx, cityId: row.node.value, districtId: undefined }
|
||||
if (canCompleteAfterSelect('city', pickCtx, row.node)) {
|
||||
this.emitValue()
|
||||
this.crumbLabels = { province: row.node.label }
|
||||
if (canCompleteAfterSelect('province', this.ctx, row.node)) {
|
||||
await this.emitValue()
|
||||
this.show = false
|
||||
return
|
||||
}
|
||||
this.currentLevel = getNextLevel('city', this.ctx) || 'city'
|
||||
this.currentLevel = getNextLevel('province', this.ctx, row.node.hasChildren) || 'city'
|
||||
} else if (row.level === 'city') {
|
||||
this.ctx = { ...this.ctx, cityId: row.node.value, districtId: undefined }
|
||||
this.crumbLabels = {
|
||||
province: this.crumbLabels.province,
|
||||
city: row.node.label,
|
||||
}
|
||||
if (canCompleteAfterSelect('city', this.ctx, row.node)) {
|
||||
await this.emitValue()
|
||||
this.show = false
|
||||
return
|
||||
}
|
||||
this.currentLevel = getNextLevel('city', this.ctx, row.node.hasChildren) || 'city'
|
||||
} else if (row.level === 'district') {
|
||||
this.ctx = { ...this.ctx, districtId: row.node.value }
|
||||
this.emitValue()
|
||||
this.crumbLabels = {
|
||||
...this.crumbLabels,
|
||||
district: row.node.label,
|
||||
}
|
||||
await this.emitValue()
|
||||
this.show = false
|
||||
return
|
||||
}
|
||||
this.keyword = ''
|
||||
await this.reloadList()
|
||||
},
|
||||
},
|
||||
}
|
||||
|
||||
@@ -92,8 +92,8 @@ import { createUserPatientApi } from '@/api/reception.js'
|
||||
import { unwrapXkApi } from '@/utils/api-response.js'
|
||||
import ClaimQrcodeModal from '@/subPackages/sub_workbench/components/claim-qrcode-modal/claim-qrcode-modal.vue'
|
||||
import {
|
||||
ensureResolvedAddress,
|
||||
formatAddressDisplay,
|
||||
resolveAddressValue,
|
||||
} from '@/subPackages/sub_clinic_salesperson/utils/address-index.js'
|
||||
// 省市区组件在业务员分包:禁止跨分包 import,走 pages.json usingComponents + componentPlaceholder
|
||||
|
||||
@@ -181,16 +181,16 @@ export default {
|
||||
}
|
||||
return []
|
||||
},
|
||||
/** 省市区选择回调:落本地 ids,并缓存中文标签供提交(避免提交时再 resolve 失败) */
|
||||
onShipRegionChange(e) {
|
||||
/** 省市区选择回调:落本地 ids,并异步 resolve 中文标签供提交 */
|
||||
async onShipRegionChange(e) {
|
||||
const val = this.unwrapRegionPickerValue(e)
|
||||
this.shipRegion = val
|
||||
const resolved = resolveAddressValue(val)
|
||||
const resolved = await ensureResolvedAddress(val)
|
||||
this.shipLabels = {
|
||||
province: (resolved.province && resolved.province.label) || '',
|
||||
city: (resolved.city && resolved.city.label) || '',
|
||||
area: (resolved.district && resolved.district.label) || '',
|
||||
region: formatAddressDisplay(val),
|
||||
region: resolved.pathLabel || formatAddressDisplay(val),
|
||||
}
|
||||
},
|
||||
validate() {
|
||||
@@ -220,11 +220,8 @@ export default {
|
||||
// 填了详细地址则必须选省市区,否则后端会静默跳过、开方订单无地址
|
||||
const shipDetail = String(this.form.ship_detail_address || '').trim()
|
||||
if (shipDetail) {
|
||||
const resolved = resolveAddressValue(this.shipRegion)
|
||||
const hasRegion = !!(this.shipLabels.province || this.shipLabels.city || this.shipLabels.area
|
||||
|| (resolved.province && resolved.province.label)
|
||||
|| (resolved.city && resolved.city.label)
|
||||
|| (resolved.district && resolved.district.label))
|
||||
|| (this.shipRegion && this.shipRegion.length >= 2))
|
||||
if (!hasRegion) {
|
||||
this.$toast('请选择省市区')
|
||||
return false
|
||||
@@ -237,7 +234,7 @@ export default {
|
||||
}
|
||||
return true
|
||||
},
|
||||
buildPayload() {
|
||||
async buildPayload() {
|
||||
const payload = {
|
||||
...this.form,
|
||||
age: Number(this.form.age),
|
||||
@@ -245,7 +242,7 @@ export default {
|
||||
waive_register_fee: this.form.waive_register_fee ? 1 : 0,
|
||||
}
|
||||
const detail = String(this.form.ship_detail_address || '').trim()
|
||||
const resolved = resolveAddressValue(this.shipRegion)
|
||||
const resolved = await ensureResolvedAddress(this.shipRegion)
|
||||
const province = this.shipLabels.province
|
||||
|| (resolved.province && resolved.province.label)
|
||||
|| ''
|
||||
@@ -255,7 +252,9 @@ export default {
|
||||
const area = this.shipLabels.area
|
||||
|| (resolved.district && resolved.district.label)
|
||||
|| ''
|
||||
const region = this.shipLabels.region || formatAddressDisplay(this.shipRegion)
|
||||
const region = this.shipLabels.region
|
||||
|| resolved.pathLabel
|
||||
|| formatAddressDisplay(this.shipRegion)
|
||||
if (detail && (province || city || area)) {
|
||||
payload.ship_province = province
|
||||
payload.ship_city = city
|
||||
@@ -271,7 +270,7 @@ export default {
|
||||
if (!this.validate()) return
|
||||
this.submitting = true
|
||||
try {
|
||||
const res = await createUserPatientApi(this.buildPayload())
|
||||
const res = await createUserPatientApi(await this.buildPayload())
|
||||
const { ok, payload, message } = unwrapXkApi(res)
|
||||
if (!ok) {
|
||||
this.$toast(message || '创建失败')
|
||||
|
||||
@@ -132,7 +132,7 @@
|
||||
<view
|
||||
class="_name"
|
||||
v-for="(ex, exIdx) in resolveExcipients(item)"
|
||||
:key="ex.drug_id || exIdx"
|
||||
:key="exIdx"
|
||||
>
|
||||
<view class="text">
|
||||
<text>{{ ex.display_name }}</text>
|
||||
|
||||
@@ -549,7 +549,7 @@
|
||||
<view
|
||||
class="tcm-tag"
|
||||
v-for="(item, exIndex) in excipients"
|
||||
:key="item.id || exIndex"
|
||||
:key="exIndex"
|
||||
:data-idx="exIndex"
|
||||
@click.stop="onExcipientTagClick"
|
||||
@longpress.stop="onExcipientTagLongPress"
|
||||
|
||||
Reference in New Issue
Block a user