| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833 |
- <template>
- <div class="p-2">
- <transition :enter-active-class="proxy?.animate.searchAnimate.enter"
- :leave-active-class="proxy?.animate.searchAnimate.leave">
- <div v-show="showSearch" class="mb-[10px] bg-white p-[20px] rounded-[4px] flex justify-between items-center shadow-sm" style="background-color: #fff; padding: 20px; border-radius: 4px; box-shadow: 0 1px 4px rgba(0,21,41,.08);">
- <div class="text-[18px] font-bold text-[#303133]" style="font-size: 18px; font-weight: bold; color: #303133;">门店管理</div>
- <div class="flex items-center gap-[10px]" style="display: flex; gap: 10px; align-items: center;">
- <el-input v-model="queryParams.storeOrContact" placeholder="搜索门店名称/联系人" prefix-icon="Search"
- style="width: 250px" clearable @keyup.enter="handleQuery" @clear="handleQuery" />
- <el-cascader v-model="searchRegionValue" :options="areaOptions" placeholder="所属城市"
- style="width: 150px" clearable @change="handleSearchAreaChange" />
- <el-select v-model="queryParams.station" placeholder="所属站点" style="width: 150px" clearable @change="handleQuery">
- <el-option v-for="site in searchSiteOptions" :key="site.value" :label="site.label" :value="site.value" />
- </el-select>
- <el-select v-model="queryParams.status" placeholder="状态" style="width: 120px" clearable @change="handleQuery">
- <el-option v-for="item in statusList" :key="item.value" :label="item.label" :value="item.value" />
- </el-select>
- <el-button type="primary" icon="Plus" @click="handleAdd" v-hasPermi="['system:store:add']">新增门店</el-button>
- </div>
- </div>
- </transition>
- <el-card shadow="never">
- <el-table v-loading="loading" border :data="storeList" @selection-change="handleSelectionChange">
- <el-table-column type="selection" width="55" align="center" />
- <el-table-column label="门店信息" align="left" width="300">
- <template #default="scope">
- <div class="store-info" style="display: flex; align-items: center; gap: 10px;">
- <div class="store-logo">
- <image-preview :src="scope.row.logoUrl" :width="50" :height="50" />
- </div>
- <div class="store-details" style="display: flex; flex-direction: column; gap: 6px;">
- <div class="store-name" style="font-size: 14px; font-weight: 500; color: #303133;">{{ scope.row.name }}</div>
- <div class="store-categories" style="display: flex; gap: 6px;">
- <el-tag size="small" type="warning" effect="plain" v-if="scope.row.tenantName">{{ scope.row.tenantName }}</el-tag>
- <el-tag size="small" type="success" effect="plain" v-if="scope.row.tenantCatergoriesName">{{ scope.row.tenantCatergoriesName }}</el-tag>
- </div>
- </div>
- </div>
- </template>
- </el-table-column>
- <el-table-column label="资质认证" align="center" width="100">
- <template #default="scope">
- <image-preview v-if="scope.row.businessLicenseUrl" :src="scope.row.businessLicenseUrl" :width="40" :height="40" />
- <span v-else>-</span>
- </template>
- </el-table-column>
- <el-table-column label="服务项目" align="center" width="200">
- <template #default="scope">
- <div class="services">
- <el-tag v-for="service in scope.row.services" :key="service" size="small"
- style="margin-right: 5px; margin-bottom: 5px">
- {{ getServiceName(service) }}
- </el-tag>
- </div>
- </template>
- </el-table-column>
- <el-table-column label="归属站点" align="center" width="150">
- <template #default="scope">
- <div>{{ scope.row.siteName }}</div>
- </template>
- </el-table-column>
- <el-table-column label="服务单" align="center" width="150">
- <template #default="scope">
- <div>{{ scope.row.serviceOrder }}</div>
- </template>
- </el-table-column>
- <el-table-column label="营业时间" align="center" width="150">
- <template #default="scope">
- <div>{{ formatTime(scope.row.startBusinessTime) }}-{{ formatTime(scope.row.endBusinessTime) }}</div>
- </template>
- </el-table-column>
- <el-table-column label="门店地址" align="center" width="300">
- <template #default="scope">
- <div>{{ scope.row.detailAddress }}</div>
- </template>
- </el-table-column>
- <el-table-column label="联系方式" align="left" width="180">
- <template #default="scope">
- <div style="display: flex; flex-direction: column; gap: 6px;">
- <div style="display: flex; align-items: center; gap: 6px; color: #606266; font-size: 14px;">
- <el-icon size="16"><User /></el-icon>
- <span>{{ scope.row.contact }}</span>
- </div>
- <div style="display: flex; align-items: center; gap: 6px; color: #409eff; font-size: 14px;">
- <el-icon size="16"><Phone /></el-icon>
- <span>{{ scope.row.contactNumber }}</span>
- </div>
- </div>
- </template>
- </el-table-column>
- <el-table-column label="有效期至" align="center" width="120">
- <template #default="scope">
- <div>{{ parseTime(scope.row.validity, '{y}-{m}-{d}') }}</div>
- </template>
- </el-table-column>
- <el-table-column label="状态" align="center" width="100">
- <template #default="scope">
- <template v-for="item in statusList" :key="item.value">
- <el-tag v-if="scope.row.status === item.value" :type="item.style">{{ item.label }}</el-tag>
- </template>
- </template>
- </el-table-column>
- <el-table-column label="操作" align="center" fixed="right" class-name="small-padding fixed-width">
- <template #default="scope">
- <el-tooltip content="详情" placement="top">
- <el-button link type="primary" icon="View" @click="handleDetail(scope.row)"></el-button>
- </el-tooltip>
- <el-tooltip content="修改" placement="top">
- <el-button link type="primary" icon="Edit" @click="handleUpdate(scope.row)"
- v-hasPermi="['system:store:edit']"></el-button>
- </el-tooltip>
- <el-tooltip content="更多" placement="top">
- <el-button link type="primary" icon="More"></el-button>
- </el-tooltip>
- </template>
- </el-table-column>
- </el-table>
- <pagination v-show="total > 0" :total="total" v-model:page="queryParams.pageNum"
- v-model:limit="queryParams.pageSize" @pagination="getList" />
- </el-card>
- <!-- 添加或修改门店管理对话框 -->
- <el-dialog :title="dialog.title" v-model="dialog.visible" width="600px" append-to-body>
- <el-form ref="storeFormRef" :model="form" :rules="rules" label-width="120px">
- <el-form-item label="门店Logo" prop="logo">
- <image-upload v-model="form.logo" :limit="1" />
- </el-form-item>
- <el-form-item label="营业执照" prop="businessLicense">
- <image-upload v-model="form.businessLicense" :limit="1" />
- </el-form-item>
- <el-form-item label="门店名称" prop="name">
- <el-input v-model="form.name" placeholder="请输入门店名称" />
- </el-form-item>
- <el-form-item label="服务项目" prop="services">
- <el-checkbox-group v-model="form.services">
- <el-checkbox v-for="service in serviceList" :key="service.id" :label="service.id" border>
- {{ service.name }}
- </el-checkbox>
- </el-checkbox-group>
- </el-form-item>
- <el-form-item label="商户分类" prop="tenantCatergories">
- <PageSelect v-model="form.tenantCatergories"
- :options="tenantCategoriesList.map(item => ({ value: item.id, label: item.name }))"
- :total="tenantCategoriesTotal" :pageSize="10" placeholder="请选择商户分类"
- @page-change="handleTenantCategoriesPageChange" @visible-change="handleTenantCategoriesVisibleChange" />
- </el-form-item>
- <el-form-item label="所属品牌" prop="tenantId">
- <PageSelect v-model="form.tenantId"
- :options="brandList.map(item => ({ value: item.tenantId, label: item.name }))" :total="brandTotal"
- :pageSize="10" placeholder="请选择所属品牌" @page-change="handleBrandPageChange"
- @visible-change="handleBrandSelectVisibleChange" />
- </el-form-item>
- <el-form-item label="营业时间" prop="startBusinessTime">
- <el-row :gutter="10">
- <el-col :span="10">
- <el-time-picker clearable v-model="form.startBusinessTime" value-format="HH:mm" placeholder="开始时间"
- style="width: 100%">
- </el-time-picker>
- </el-col>
- <el-col :span="4" style="text-align: center; line-height: 40px">
- 至
- </el-col>
- <el-col :span="10">
- <el-time-picker clearable v-model="form.endBusinessTime" value-format="HH:mm" placeholder="结束时间"
- style="width: 100%">
- </el-time-picker>
- </el-col>
- </el-row>
- </el-form-item>
- <el-form-item label="联系人" prop="contact">
- <el-input v-model="form.contact" placeholder="请输入联系人" />
- </el-form-item>
- <el-form-item label="联系电话" prop="contactNumber">
- <el-input v-model="form.contactNumber" placeholder="请输入联系电话" />
- </el-form-item>
- <el-form-item label="有效期至" prop="validity">
- <el-date-picker clearable v-model="form.validity" type="date" value-format="YYYY-MM-DD" placeholder="请选择有效期至"
- style="width: 100%">
- </el-date-picker>
- </el-form-item>
- <el-row :gutter="10">
- <el-col :span="12">
- <el-form-item label="所在区域" prop="regionId">
- <el-cascader v-model="regionValue" :options="areaOptions" placeholder="选择区域" style="width: 100%"
- @change="handleAreaChange" />
- </el-form-item>
- </el-col>
- <el-col :span="12">
- <el-form-item label="归属站点" prop="site">
- <el-select v-model="form.site" placeholder="选择站点" :disabled="!form.regionId">
- <el-option v-for="site in siteOptions" :key="site.value" :label="site.label" :value="site.value" />
- </el-select>
- </el-form-item>
- </el-col>
- </el-row>
- <el-form-item label="详细地址">
- <el-row :gutter="10" style="margin-bottom: 10px">
- <el-col :span="24">
- <el-cascader v-model="addressCascaderValue" :options="regionData" placeholder="选择省市区"
- style="width: 100%" />
- </el-col>
- </el-row>
- <el-input v-model="form.detailAddress" type="textarea" placeholder="输入详细地址" rows="3" style="width: 100%" />
- </el-form-item>
- <el-form-item>
- <el-button type="primary" style="width: 100%" @click="getGeolocation">获取经纬度</el-button>
- </el-form-item>
- <el-row :gutter="10">
- <el-col :span="12">
- <el-form-item label="经度" prop="longitude">
- <el-input v-model="form.longitude" placeholder="请获取/输入位置经度" />
- </el-form-item>
- </el-col>
- <el-col :span="12">
- <el-form-item label="纬度" prop="latitude">
- <el-input v-model="form.latitude" placeholder="请获取/输入位置纬度" />
- </el-form-item>
- </el-col>
- </el-row>
- </el-form>
- <template #footer>
- <div class="dialog-footer">
- <el-button :loading="buttonLoading" type="primary" @click="submitForm">确 定</el-button>
- <el-button @click="cancel">取 消</el-button>
- </div>
- </template>
- </el-dialog>
- <!-- 门店详情对话框 -->
- <el-dialog :title="detailDialog.title" v-model="detailDialog.visible" width="800px" append-to-body>
- <el-tabs v-model="activeTab" style="padding: 0 10px;">
- <el-tab-pane label="基础信息" name="basic">
- <el-descriptions :column="2" border>
- <el-descriptions-item label="门店名称">{{ detailData.name }}</el-descriptions-item>
- <el-descriptions-item label="商户分类">{{ detailData.tenantCatergoriesName || '-' }}</el-descriptions-item>
- <el-descriptions-item label="所属品牌">{{ detailData.tenantName || '-' }}</el-descriptions-item>
- <el-descriptions-item label="营业时间">{{ formatTime(detailData.startBusinessTime) }} - {{ formatTime(detailData.endBusinessTime) }}</el-descriptions-item>
- <el-descriptions-item label="有效期至">{{ parseTime(detailData.validity, '{y}-{m}-{d}') }}</el-descriptions-item>
- <el-descriptions-item label="联系人">{{ detailData.contact }}</el-descriptions-item>
- <el-descriptions-item label="联系电话">{{ detailData.contactNumber }}</el-descriptions-item>
- <el-descriptions-item label="所在区域">{{ detailData.regionName || '北京市朝阳区' }}</el-descriptions-item>
- <el-descriptions-item label="详细地址">{{ detailData.detailAddress }}</el-descriptions-item>
- <el-descriptions-item label="营业执照">
- <image-preview v-if="detailData.businessLicenseUrl" :src="detailData.businessLicenseUrl" :width="80" :height="60" />
- <span v-else>-</span>
- </el-descriptions-item>
- </el-descriptions>
- </el-tab-pane>
- <el-tab-pane label="服务订单记录" name="orders">
- <el-table :data="orderList" border style="width: 100%">
- <el-table-column label="订单号" prop="orderNo" min-width="150" />
- <el-table-column label="服务项目" prop="service" min-width="120" />
- <el-table-column label="客户" prop="customer" min-width="100" />
- <el-table-column label="金额" prop="amount" min-width="100" />
- <el-table-column label="下单时间" prop="time" min-width="160" />
- <el-table-column label="状态" align="center" width="100">
- <template #default="scope">
- <el-tag :type="scope.row.statusType" effect="plain" size="small">{{ scope.row.status }}</el-tag>
- </template>
- </el-table-column>
- </el-table>
- </el-tab-pane>
- </el-tabs>
- <template #footer>
- <div class="dialog-footer">
- <el-button @click="detailDialog.visible = false">关 闭</el-button>
- </div>
- </template>
- </el-dialog>
- </div>
- </template>
- <script setup name="Store" lang="ts">
- import { listStore, getStore, delStore, addStore, updateStore, listStoreStatus } from '@/api/system/store';
- import { StoreVO, StoreQuery, StoreForm, StoreStatusVO, SysStorePageBo } from '@/api/system/store/types';
- import { listOnStore } from '@/api/system/tenant';
- import { listOnStore as listTenantCategoriesOnStore } from '@/api/system/tenantCategories';
- import { listOnStore as listServiceOnStore } from '@/api/service/list';
- import { listOnStore as listAreaStationOnStore } from '@/api/system/areaStation';
- import { SysAreaStationOnStoreVo } from '@/api/system/areaStation/types';
- import { regionData, codeToText, textToCode } from 'element-china-area-data';
- import PageSelect from '@/components/PageSelect/index.vue';
- const { proxy } = getCurrentInstance() as ComponentInternalInstance;
- const storeList = ref<StoreVO[]>([]);
- const buttonLoading = ref(false);
- const loading = ref(true);
- const showSearch = ref(true);
- const ids = ref<Array<string | number>>([]);
- const single = ref(true);
- const multiple = ref(true);
- const total = ref(0);
- const queryFormRef = ref<ElFormInstance>();
- const storeFormRef = ref<ElFormInstance>();
- const brandSelectRef = ref<any>(null);
- const searchRegionValue = ref<any[]>([]); // 搜索的区域值
- const searchSiteOptions = ref<any[]>([]); // 搜索的站点选项
- /** 处理搜索区域选择变化 */
- const handleSearchAreaChange = (value: any[]) => {
- // 清空级联站点
- queryParams.value.station = undefined;
- if (value && value.length > 0) {
- const areaId = value[value.length - 1];
- queryParams.value.area = areaId;
- searchSiteOptions.value = areaStationList.value
- .filter((item: any) => item.type === 2 && String(item.parentId) === String(areaId))
- .map((item: any) => ({
- value: item.id,
- label: item.name
- }));
- } else {
- queryParams.value.area = undefined;
- searchSiteOptions.value = [];
- }
- handleQuery();
- };
- // 新增的响应式变量
- const regionValue = ref<any[]>([]);
- const province = ref('');
- const city = ref('');
- const district = ref('');
- const addressCascaderValue = ref<any[]>([]); // 省市区级联选择器值
- const brandList = ref<any[]>([]); // 品牌列表
- const brandLoading = ref(false); // 品牌加载状态
- const currentPage = ref(1); // 当前页码
- const brandKeyword = ref(''); // 搜索关键词
- const brandSelectVisible = ref(false); // 品牌选择框可见状态
- const brandTotal = ref(0); // 品牌总数
- const serviceList = ref<any[]>([]); // 服务项目列表
- const statusList = ref<StoreStatusVO[]>([]); // 状态列表
- const tenantCategoriesList = ref<any[]>([]); // 商户分类列表
- const tenantCategoriesTotal = ref(0); // 商户分类总数
- const areaStationList = ref<SysAreaStationOnStoreVo[]>([]); // 区域站点列表
- const areaOptions = ref<any[]>([]); // 所在区域树形选项
- const siteOptions = ref<any[]>([]); // 归属站点选项
- const dialog = reactive<DialogOption>({
- visible: false,
- title: ''
- });
- const detailDialog = reactive({
- visible: false,
- title: '门店详情'
- });
- const activeTab = ref('basic');
- const detailData = ref<any>({});
- const orderList = ref([
- { orderNo: 'ORD202402040001', service: '洗澡美容', customer: '张三', amount: '¥128', time: '2024-02-04 10:00', status: '已完成', statusType: 'success' },
- { orderNo: 'ORD202402040002', service: '寄养服务', customer: '李四', amount: '¥500', time: '2024-02-03 14:30', status: '已完成', statusType: 'success' },
- { orderNo: 'ORD202402030005', service: '疫苗注射', customer: '王五', amount: '¥80', time: '2024-02-01 09:00', status: '已取消', statusType: 'info' }
- ]);
- /** 详情按钮操作 */
- const handleDetail = async (row: StoreVO) => {
- const res = await getStore(row.id);
- // 合并列表里的关联数据,以便能够展示名称等额外字段
- detailData.value = { ...row, ...res.data };
- activeTab.value = 'basic';
- detailDialog.visible = true;
- };
- const initFormData: StoreForm = {
- id: undefined,
- logo: undefined,
- businessLicense: undefined,
- name: undefined,
- tenantCatergories: undefined,
- startBusinessTime: undefined,
- endBusinessTime: undefined,
- contact: undefined,
- contactNumber: undefined,
- validity: undefined,
- site: undefined,
- detailAddress: undefined,
- status: undefined,
- longitude: undefined,
- latitude: undefined,
- tenantId: undefined,
- services: [],
- regionId: undefined,
- }
- const data = reactive<PageData<StoreForm, SysStorePageBo>>({
- form: { ...initFormData },
- queryParams: {
- pageNum: 1,
- pageSize: 10,
- storeOrContact: undefined,
- area: undefined,
- station: undefined,
- status: undefined,
- params: {
- }
- },
- rules: {
- id: [
- { required: true, message: "序号不能为空", trigger: "blur" }
- ],
- businessLicense: [
- { required: true, message: "营业执照不能为空", trigger: "blur" }
- ],
- name: [
- { required: true, message: "门店名称不能为空", trigger: "blur" }
- ],
- tenantCatergories: [
- { required: true, message: "商户分类不能为空", trigger: "change" }
- ],
- startBusinessTime: [
- { required: true, message: "开始营业时间不能为空", trigger: "blur" }
- ],
- endBusinessTime: [
- { required: true, message: "结束营业时间不能为空", trigger: "blur" }
- ],
- contact: [
- { required: true, message: "联系人不能为空", trigger: "blur" }
- ],
- contactNumber: [
- { required: true, message: "联系电话不能为空", trigger: "blur" }
- ],
- validity: [
- { required: true, message: "有效期至不能为空", trigger: "blur" }
- ],
- tenantId: [
- { required: true, message: "租户编号不能为空", trigger: "change" }
- ],
- regionId: [
- { required: true, message: "所在区域不能为空", trigger: "change" }
- ],
- site: [
- { required: true, message: "归属站点不能为空", trigger: "change" }
- ],
- }
- });
- const { queryParams, form, rules } = toRefs(data);
- /** 查询门店管理列表 */
- const getList = async () => {
- loading.value = true;
- const res = await listStore(queryParams.value);
- storeList.value = res.rows;
- total.value = res.total;
- loading.value = false;
- }
- /** 取消按钮 */
- const cancel = () => {
- reset();
- dialog.visible = false;
- }
- /** 表单重置 */
- const reset = () => {
- form.value = { ...initFormData };
- // 重置新增的变量
- regionValue.value = [];
- province.value = '';
- city.value = '';
- district.value = '';
- addressCascaderValue.value = [];
- storeFormRef.value?.resetFields();
- }
- /** 搜索按钮操作 */
- const handleQuery = () => {
- queryParams.value.pageNum = 1;
- getList();
- }
- /** 重置按钮操作 */
- const resetQuery = () => {
- searchRegionValue.value = [];
- searchSiteOptions.value = [];
- queryParams.value.storeOrContact = undefined;
- queryParams.value.area = undefined;
- queryParams.value.station = undefined;
- queryParams.value.status = undefined;
- handleQuery();
- }
- /** 多选框选中数据 */
- const handleSelectionChange = (selection: StoreVO[]) => {
- ids.value = selection.map(item => item.id);
- single.value = selection.length != 1;
- multiple.value = !selection.length;
- }
- /** 新增按钮操作 */
- const handleAdd = () => {
- reset();
- dialog.visible = true;
- dialog.title = "添加门店管理";
- }
- /** 修改按钮操作 */
- const handleUpdate = async (row?: StoreVO) => {
- reset();
- const _id = row?.id || ids.value[0]
- const res = await getStore(_id);
- Object.assign(form.value, res.data);
- dialog.visible = true;
- dialog.title = "修改门店管理";
- }
- /** 提交按钮 */
- const submitForm = () => {
- storeFormRef.value?.validate(async (valid: boolean) => {
- if (valid) {
- buttonLoading.value = true;
- if (form.value.id) {
- await updateStore(form.value).finally(() => buttonLoading.value = false);
- } else {
- await addStore(form.value).finally(() => buttonLoading.value = false);
- }
- proxy?.$modal.msgSuccess("操作成功");
- dialog.visible = false;
- await getList();
- }
- });
- }
- /** 删除按钮操作 */
- const handleDelete = async (row?: StoreVO) => {
- const _ids = row?.id || ids.value;
- await proxy?.$modal.confirm('是否确认删除门店管理编号为"' + _ids + '"的数据项?').finally(() => loading.value = false);
- await delStore(_ids);
- proxy?.$modal.msgSuccess("删除成功");
- await getList();
- }
- /** 导出按钮操作 */
- const handleExport = () => {
- proxy?.download('system/store/export', {
- ...queryParams.value
- }, `store_${new Date().getTime()}.xlsx`)
- }
- /** 获取经纬度 */
- const getGeolocation = () => {
- if ('geolocation' in navigator) {
- navigator.geolocation.getCurrentPosition(
- (position) => {
- form.value.longitude = position.coords.longitude.toFixed(6);
- form.value.latitude = position.coords.latitude.toFixed(6);
- proxy?.$modal.msgSuccess('获取经纬度成功');
- },
- (error) => {
- let errorMessage = '获取位置失败';
- switch (error.code) {
- case error.PERMISSION_DENIED:
- errorMessage = '用户拒绝了地理定位请求';
- break;
- case error.POSITION_UNAVAILABLE:
- errorMessage = '位置信息不可用';
- break;
- case error.TIMEOUT:
- errorMessage = '获取位置超时';
- break;
- case error.UNKNOWN_ERROR:
- errorMessage = '未知错误';
- break;
- }
- proxy?.$modal.msgError(errorMessage);
- }
- );
- } else {
- proxy?.$modal.msgError('您的浏览器不支持地理定位');
- }
- };
- /** 获取品牌列表 */
- const getBrandList = async (pageNum = 1, keyword = '', append = false) => {
- brandLoading.value = true;
- // 确保参数格式正确,直接传递数字类型的pageNum
- const res = await listOnStore({ pageNum: pageNum, pageSize: 10 });
- if (res.code === 200) {
- if (append) {
- // 追加模式,用于分页加载
- brandList.value = [...brandList.value, ...res.rows];
- } else {
- // 替换模式,用于初始加载或搜索
- brandList.value = res.rows;
- }
- // 存储总数
- brandTotal.value = res.total || 0;
- console.log('总数', brandTotal.value);
- }
- brandLoading.value = false;
- };
- /** 获取服务项目列表 */
- const getServiceList = async () => {
- try {
- const res = await listServiceOnStore();
- // 转换数据格式,适配checkbox组件
- serviceList.value = res.data || res;
- } catch (error) {
- console.error('获取服务项目列表失败:', error);
- }
- };
- /** 获取区域站点列表 */
- const getAreaStationList = async () => {
- try {
- const res = await listAreaStationOnStore();
- const data = res.data || res;
- areaStationList.value = data;
- // 分离所在区域数据(type为0或1)
- const areaData = data.filter((item: any) => item.type === 0 || item.type === 1);
- // 构建树形结构
- areaOptions.value = buildTree(areaData, 0);
- // 初始化站点数据为空
- siteOptions.value = [];
- } catch (error) {
- console.error('获取区域站点列表失败:', error);
- }
- };
- /** 构建树形结构 */
- const buildTree = (data: any[], parentId: any): any[] => {
- return data
- .filter(item => String(item.parentId) === String(parentId))
- .map(item => ({
- value: item.id,
- label: item.name,
- children: buildTree(data, item.id)
- }));
- };
- /** 处理所在区域选择变化 */
- const handleAreaChange = (value: any[]) => {
- // 清空归属站点选择
- form.value.site = undefined;
- if (value && value.length > 0) {
- // 获取最后一级的id
- const areaId = value[value.length - 1];
- // 更新regionId
- form.value.regionId = areaId;
- // 过滤出parentId等于areaId的站点
- siteOptions.value = areaStationList.value
- .filter((item: any) => item.type === 2 && String(item.parentId) === String(areaId))
- .map((item: any) => ({
- value: item.id,
- label: item.name
- }));
- } else {
- // 如果没有选择区域,清空站点选项和regionId
- form.value.regionId = undefined;
- siteOptions.value = [];
- }
- };
- /** 获取商户分类列表 */
- const getTenantCategoriesList = async (pageNum = 1) => {
- try {
- const res = await listTenantCategoriesOnStore({ pageNum, pageSize: 10 });
- if (res.code === 200) {
- tenantCategoriesList.value = res.rows;
- tenantCategoriesTotal.value = res.total || 0;
- }
- } catch (error) {
- console.error('获取商户分类列表失败:', error);
- }
- };
- /** 处理品牌页面切换 */
- const handleBrandPageChange = (page: number) => {
- // 确保page是数字类型
- const pageNum = Number(page);
- currentPage.value = pageNum;
- getBrandList(pageNum, brandKeyword.value, false);
- };
- /** 处理商户分类分页 */
- const handleTenantCategoriesPageChange = (page: number) => {
- // 确保page是数字类型
- const pageNum = Number(page);
- getTenantCategoriesList(pageNum);
- };
- /** 处理商户分类选择框可见性变化 */
- const handleTenantCategoriesVisibleChange = (visible: boolean) => {
- if (visible) {
- getTenantCategoriesList(1);
- }
- };
- /** 远程搜索方法 */
- const remoteMethod = (query: string) => {
- brandKeyword.value = query;
- currentPage.value = 1;
- getBrandList(1, query, false);
- };
- /** 处理品牌选择框显示状态变化 */
- const handleBrandSelectVisibleChange = (visible: boolean) => {
- brandSelectVisible.value = visible;
- if (visible) {
- // 选择框显示时,重置页码并重新加载数据
- currentPage.value = 1;
- getBrandList(1, brandKeyword.value, false);
- }
- };
- // 监听省市区选择变化,自动追加到详细地址
- watch(
- addressCascaderValue,
- (newValue) => {
- if (newValue && newValue.length > 0) {
- // 将选中的省市区文本追加到详细地址
- const addressText = newValue.map(code => codeToText[code]).join('');
- if (form.value.detailAddress) {
- // 如果已有详细地址,将省市区放在前面
- form.value.detailAddress = addressText + form.value.detailAddress;
- } else {
- form.value.detailAddress = addressText;
- }
- }
- },
- { deep: true }
- );
- /** 获取服务项目名称 */
- const getServiceName = (serviceId: number): string => {
- const service = serviceList.value.find(item => item.id === serviceId);
- return service ? service.name : String(serviceId);
- };
- /** 获取状态列表 */
- const getStatusList = async () => {
- try {
- const res: any = await listStoreStatus();
- // 兼容可能的不同响应体结构
- statusList.value = res.data || res.rows || res;
- } catch (error) {
- console.error('获取状态列表失败:', error);
- }
- };
- /** 格式化时间为时分 */
- const formatTime = (time: string | number): string => {
- if (!time) return '';
- // 处理时间戳或日期字符串
- const date = new Date(time);
- // 检查是否是有效日期
- if (isNaN(date.getTime())) return '';
- // 格式化为 HH:mm
- const hours = date.getHours().toString().padStart(2, '0');
- const minutes = date.getMinutes().toString().padStart(2, '0');
- return `${hours}:${minutes}`;
- };
- onMounted(() => {
- getList();
- getBrandList();
- getServiceList();
- getAreaStationList();
- getStatusList();
- });
- </script>
- <style scoped>
- .brand-pagination {
- margin-top: 10px;
- padding-top: 10px;
- border-top: 1px solid #ebeef5;
- text-align: center;
- }
- .custom-pagination {
- display: flex;
- align-items: center;
- justify-content: center;
- gap: 10px;
- font-size: 14px;
- }
- .page-arrow {
- cursor: pointer;
- color: #606266;
- user-select: none;
- padding: 2px 8px;
- transition: color 0.3s;
- }
- .page-arrow:hover:not(.disabled) {
- color: #409eff;
- }
- .page-arrow.disabled {
- color: #c0c4cc;
- cursor: not-allowed;
- }
- .page-number {
- cursor: pointer;
- color: #606266;
- padding: 2px 8px;
- transition: all 0.3s;
- }
- .page-number:hover {
- color: #409eff;
- }
- .page-number.active {
- color: #409eff;
- font-weight: bold;
- }
- .total-text {
- margin-left: 15px;
- font-size: 12px;
- color: #909399;
- }
- </style>
|