first
This commit is contained in:
306
admin-web/src/pages/warehouses/index.vue
Normal file
306
admin-web/src/pages/warehouses/index.vue
Normal 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>
|
||||
Reference in New Issue
Block a user