This commit is contained in:
wushumin
2026-05-11 15:28:27 +08:00
commit 9aac78b8da
289 changed files with 67193 additions and 0 deletions

View File

@@ -0,0 +1,306 @@
<script setup lang="ts">
import { onMounted, reactive, ref } from "vue";
import { ElMessage } from "element-plus";
import {
adminApi,
type AdminWarehouseItem,
type AdminWarehouseOverviewCard,
type AdminWarehousePayload,
} from "../../api/admin";
import OrderStatusTag from "../../components/OrderStatusTag.vue";
const loading = ref(false);
const submitting = ref(false);
const dialogVisible = ref(false);
const cards = ref<AdminWarehouseOverviewCard[]>([]);
const warehouses = ref<AdminWarehouseItem[]>([]);
const categories = ref<Array<{ id: number; name: string }>>([]);
const serviceAreaProvincesText = ref("");
const serviceAreaCitiesText = ref("");
const form = reactive<AdminWarehousePayload>({
warehouse_name: "",
warehouse_code: "",
service_provider: "anxinyan",
receiver_name: "",
receiver_mobile: "",
province: "广东省",
city: "深圳市",
district: "南山区",
detail_address: "",
service_time: "周一至周日 09:30-18:30",
notice: "",
supported_category_ids: [],
service_area_provinces: [],
service_area_cities: [],
status: "enabled",
is_default: true,
sort_order: 0,
remark: "",
});
async function fetchAll() {
loading.value = true;
try {
const [overviewRes, warehousesRes] = await Promise.all([
adminApi.getWarehouseOverview(),
adminApi.getWarehouses(),
]);
cards.value = overviewRes.data.cards;
warehouses.value = warehousesRes.data.list;
categories.value = warehousesRes.data.category_options;
} catch (error) {
console.error(error);
ElMessage.error("仓库中心数据加载失败");
} finally {
loading.value = false;
}
}
function parseAreaText(value: string) {
return value
.split(/[\n,]/)
.map((item) => item.trim())
.filter(Boolean);
}
function openDialog(row?: AdminWarehouseItem) {
if (row) {
form.id = row.id;
form.warehouse_name = row.warehouse_name;
form.warehouse_code = row.warehouse_code;
form.service_provider = row.service_provider;
form.receiver_name = row.receiver_name;
form.receiver_mobile = row.receiver_mobile;
form.province = row.province;
form.city = row.city;
form.district = row.district;
form.detail_address = row.detail_address;
form.service_time = row.service_time;
form.notice = row.notice;
form.supported_category_ids = [...row.supported_category_ids];
form.service_area_provinces = [...row.service_area_provinces];
form.service_area_cities = [...row.service_area_cities];
form.status = row.status;
form.is_default = row.is_default;
form.sort_order = row.sort_order;
form.remark = row.remark;
serviceAreaProvincesText.value = row.service_area_provinces.join("");
serviceAreaCitiesText.value = row.service_area_cities.join("");
} else {
form.id = undefined;
form.warehouse_name = "";
form.warehouse_code = "";
form.service_provider = "anxinyan";
form.receiver_name = "";
form.receiver_mobile = "";
form.province = "广东省";
form.city = "深圳市";
form.district = "南山区";
form.detail_address = "";
form.service_time = "周一至周日 09:30-18:30";
form.notice = "";
form.supported_category_ids = [];
form.service_area_provinces = [];
form.service_area_cities = [];
form.status = "enabled";
form.is_default = true;
form.sort_order = 0;
form.remark = "";
serviceAreaProvincesText.value = "";
serviceAreaCitiesText.value = "";
}
dialogVisible.value = true;
}
async function submit() {
submitting.value = true;
try {
await adminApi.saveWarehouse({
...form,
service_area_provinces: parseAreaText(serviceAreaProvincesText.value),
service_area_cities: parseAreaText(serviceAreaCitiesText.value),
});
ElMessage.success(form.id ? "仓库已更新" : "仓库已创建");
dialogVisible.value = false;
await fetchAll();
} catch (error) {
console.error(error);
ElMessage.error("仓库保存失败");
} finally {
submitting.value = false;
}
}
onMounted(fetchAll);
</script>
<template>
<div v-loading="loading">
<div class="metric-grid" style="margin-bottom: 18px">
<div v-for="item in cards" :key="item.title" class="metric-card">
<div class="metric-card__label">{{ item.title }}</div>
<div class="metric-card__value">{{ item.value }}</div>
<div class="metric-card__desc">{{ item.desc }}</div>
</div>
</div>
<el-card class="panel-card" shadow="never">
<div class="filters-row" style="justify-content: space-between;">
<div style="color: var(--admin-text-subtle);">
维护用户寄送页展示的收货仓库与检测中心地址当前按服务类型匹配默认仓库并预留按品类扩展能力
</div>
<el-button type="primary" @click="openDialog()">新增仓库</el-button>
</div>
</el-card>
<el-card class="panel-card orders-table" shadow="never">
<el-table :data="warehouses" stripe>
<el-table-column prop="warehouse_name" label="仓库名称" min-width="180" />
<el-table-column prop="warehouse_code" label="仓库编码" min-width="150" />
<el-table-column prop="service_provider_text" label="服务归属" min-width="120" />
<el-table-column prop="receiver_name" label="收件人" min-width="120" />
<el-table-column prop="receiver_mobile" label="联系电话" min-width="130" />
<el-table-column prop="full_address" label="地址" min-width="260" />
<el-table-column label="适用品类" min-width="220">
<template #default="{ row }">
<el-space wrap>
<el-tag v-if="row.supported_category_names.length === 0" type="info" round>全部品类</el-tag>
<el-tag v-for="item in row.supported_category_names" :key="item" type="warning" round>{{ item }}</el-tag>
</el-space>
</template>
</el-table-column>
<el-table-column label="服务地区" min-width="220">
<template #default="{ row }">
<el-space wrap>
<el-tag v-if="row.service_area_provinces.length === 0 && row.service_area_cities.length === 0" type="info" round>全国推荐</el-tag>
<el-tag v-for="item in row.service_area_provinces" :key="`province-${item}`" round>{{ item }}</el-tag>
<el-tag v-for="item in row.service_area_cities" :key="`city-${item}`" type="success" round>{{ item }}</el-tag>
</el-space>
</template>
</el-table-column>
<el-table-column label="状态" min-width="140">
<template #default="{ row }">
<OrderStatusTag :status="row.is_default ? `${row.status_text} / 默认` : row.status_text" />
</template>
</el-table-column>
<el-table-column prop="service_time" label="服务时间" min-width="180" />
<el-table-column label="操作" fixed="right" width="100">
<template #default="{ row }">
<el-button link type="primary" @click="openDialog(row)">编辑</el-button>
</template>
</el-table-column>
</el-table>
</el-card>
<el-dialog v-model="dialogVisible" :title="form.id ? '编辑仓库' : '新增仓库'" width="720px">
<el-form label-position="top">
<el-row :gutter="16">
<el-col :span="12">
<el-form-item label="仓库名称">
<el-input v-model="form.warehouse_name" placeholder="请输入仓库名称" />
</el-form-item>
</el-col>
<el-col :span="12">
<el-form-item label="仓库编码">
<el-input v-model="form.warehouse_code" placeholder="可留空,系统自动生成" />
</el-form-item>
</el-col>
<el-col :span="12">
<el-form-item label="服务归属">
<el-select v-model="form.service_provider" style="width: 100%">
<el-option label="实物鉴定" value="anxinyan" />
<el-option label="中检鉴定" value="zhongjian" />
</el-select>
</el-form-item>
</el-col>
<el-col :span="12">
<el-form-item label="排序值">
<el-input v-model.number="form.sort_order" type="number" placeholder="越小越靠前" />
</el-form-item>
</el-col>
<el-col :span="12">
<el-form-item label="收件人">
<el-input v-model="form.receiver_name" placeholder="请输入收件人" />
</el-form-item>
</el-col>
<el-col :span="12">
<el-form-item label="联系电话">
<el-input v-model="form.receiver_mobile" placeholder="请输入联系电话" />
</el-form-item>
</el-col>
<el-col :span="8">
<el-form-item label="省份">
<el-input v-model="form.province" placeholder="请输入省份" />
</el-form-item>
</el-col>
<el-col :span="8">
<el-form-item label="城市">
<el-input v-model="form.city" placeholder="请输入城市" />
</el-form-item>
</el-col>
<el-col :span="8">
<el-form-item label="区县">
<el-input v-model="form.district" placeholder="请输入区县" />
</el-form-item>
</el-col>
<el-col :span="24">
<el-form-item label="详细地址">
<el-input v-model="form.detail_address" placeholder="请输入详细地址" />
</el-form-item>
</el-col>
<el-col :span="24">
<el-form-item label="服务时间">
<el-input v-model="form.service_time" placeholder="例如:周一至周日 09:30-18:30" />
</el-form-item>
</el-col>
<el-col :span="24">
<el-form-item label="适用品类">
<el-select v-model="form.supported_category_ids" multiple collapse-tags collapse-tags-tooltip style="width: 100%" placeholder="不选则代表全部品类">
<el-option v-for="item in categories" :key="item.id" :label="item.name" :value="item.id" />
</el-select>
</el-form-item>
</el-col>
<el-col :span="24">
<el-form-item label="寄送提示">
<el-input v-model="form.notice" type="textarea" :rows="4" placeholder="请输入寄送须知、单号说明等文案" />
</el-form-item>
</el-col>
<el-col :span="12">
<el-form-item label="推荐省份">
<el-input v-model="serviceAreaProvincesText" type="textarea" :rows="4" placeholder="多个省份可用逗号或换行分隔;留空代表不限制省份" />
</el-form-item>
</el-col>
<el-col :span="12">
<el-form-item label="推荐城市">
<el-input v-model="serviceAreaCitiesText" type="textarea" :rows="4" placeholder="多个城市可用逗号或换行分隔;优先级高于省份" />
</el-form-item>
</el-col>
<el-col :span="24">
<el-form-item label="备注">
<el-input v-model="form.remark" placeholder="可填写仓库说明、备用信息等" />
</el-form-item>
</el-col>
<el-col :span="12">
<el-form-item label="状态">
<el-radio-group v-model="form.status">
<el-radio value="enabled">启用</el-radio>
<el-radio value="disabled">停用</el-radio>
</el-radio-group>
</el-form-item>
</el-col>
<el-col :span="12">
<el-form-item label="默认仓库">
<el-switch v-model="form.is_default" inline-prompt active-text="默认" inactive-text="普通" />
</el-form-item>
</el-col>
</el-row>
</el-form>
<template #footer>
<el-button @click="dialogVisible = false">取消</el-button>
<el-button type="primary" :loading="submitting" @click="submit">保存</el-button>
</template>
</el-dialog>
</div>
</template>