|
@@ -1,9 +1,20 @@
|
|
|
<template>
|
|
<template>
|
|
|
<div class="table-box classify-management">
|
|
<div class="table-box classify-management">
|
|
|
- <ProTable ref="proTable" :columns="columns" :request-api="getTableList" :init-param="initParam">
|
|
|
|
|
|
|
+ <ProTable
|
|
|
|
|
+ ref="proTable"
|
|
|
|
|
+ :columns="columns"
|
|
|
|
|
+ :request-api="getTableList"
|
|
|
|
|
+ :init-param="initParam"
|
|
|
|
|
+ :pagination="false"
|
|
|
|
|
+ @drag-sort="onDragSortEnd"
|
|
|
|
|
+ >
|
|
|
<template #tableHeader>
|
|
<template #tableHeader>
|
|
|
<div class="table-header">
|
|
<div class="table-header">
|
|
|
- <el-button type="primary" @click="handleNew"> 新建 </el-button>
|
|
|
|
|
|
|
+ <div class="table-header-left">
|
|
|
|
|
+ <el-button type="primary" @click="handleNew"> 新建 </el-button>
|
|
|
|
|
+ <span v-if="sortSaving" class="sort-saving-tip">正在保存排序…</span>
|
|
|
|
|
+ <span v-else class="sort-tip">拖动「排序」列图标可调整顺序,松手后自动保存</span>
|
|
|
|
|
+ </div>
|
|
|
</div>
|
|
</div>
|
|
|
</template>
|
|
</template>
|
|
|
<template #isDisplay="{ row }">
|
|
<template #isDisplay="{ row }">
|
|
@@ -77,6 +88,7 @@
|
|
|
<script setup lang="ts">
|
|
<script setup lang="ts">
|
|
|
import { ref, reactive } from "vue";
|
|
import { ref, reactive } from "vue";
|
|
|
import { ElMessage, ElMessageBox } from "element-plus";
|
|
import { ElMessage, ElMessageBox } from "element-plus";
|
|
|
|
|
+import { useDebounceFn } from "@vueuse/core";
|
|
|
import type { FormInstance, FormRules } from "element-plus";
|
|
import type { FormInstance, FormRules } from "element-plus";
|
|
|
import type { UploadRequestOptions, UploadUserFile } from "element-plus";
|
|
import type { UploadRequestOptions, UploadUserFile } from "element-plus";
|
|
|
import { Plus } from "@element-plus/icons-vue";
|
|
import { Plus } from "@element-plus/icons-vue";
|
|
@@ -88,7 +100,8 @@ import {
|
|
|
scheduleAdd,
|
|
scheduleAdd,
|
|
|
scheduleEdit,
|
|
scheduleEdit,
|
|
|
scheduleDetail,
|
|
scheduleDetail,
|
|
|
- getHasReservation
|
|
|
|
|
|
|
+ getHasReservation,
|
|
|
|
|
+ scheduleSort
|
|
|
} from "@/api/modules/scheduledService";
|
|
} from "@/api/modules/scheduledService";
|
|
|
import { uploadFileToOss } from "@/api/upload.js";
|
|
import { uploadFileToOss } from "@/api/upload.js";
|
|
|
import { localGet } from "@/utils";
|
|
import { localGet } from "@/utils";
|
|
@@ -103,8 +116,10 @@ export interface CategoryRow {
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
const proTable = ref<ProTableInstance>();
|
|
const proTable = ref<ProTableInstance>();
|
|
|
|
|
+const sortSaving = ref(false);
|
|
|
|
|
|
|
|
const columns: ColumnProps<CategoryRow>[] = [
|
|
const columns: ColumnProps<CategoryRow>[] = [
|
|
|
|
|
+ { type: "sort", label: "排序", width: 64, align: "center" },
|
|
|
{ prop: "_seq", label: "序号", width: 60, align: "center" },
|
|
{ prop: "_seq", label: "序号", width: 60, align: "center" },
|
|
|
{ prop: "name", label: "名称" },
|
|
{ prop: "name", label: "名称" },
|
|
|
{ prop: "maxBookingTime", label: "最长预订时间(分钟)", align: "center" },
|
|
{ prop: "maxBookingTime", label: "最长预订时间(分钟)", align: "center" },
|
|
@@ -112,8 +127,11 @@ const columns: ColumnProps<CategoryRow>[] = [
|
|
|
{ prop: "operation", label: "操作", fixed: "right", width: 140, align: "center" }
|
|
{ prop: "operation", label: "操作", fixed: "right", width: 140, align: "center" }
|
|
|
];
|
|
];
|
|
|
|
|
|
|
|
|
|
+/** 关闭分页并一次拉全量,拖拽排序后提交的 categoryIds 与门店顺序一致 */
|
|
|
const initParam = reactive({
|
|
const initParam = reactive({
|
|
|
- storeId: localGet("geeker-user")?.userInfo?.storeId ?? localGet("createdId") ?? ""
|
|
|
|
|
|
|
+ storeId: localGet("geeker-user")?.userInfo?.storeId ?? localGet("createdId") ?? "",
|
|
|
|
|
+ pageNum: 1,
|
|
|
|
|
+ pageSize: 500
|
|
|
});
|
|
});
|
|
|
|
|
|
|
|
function mapCategoryItem(item: any): CategoryRow {
|
|
function mapCategoryItem(item: any): CategoryRow {
|
|
@@ -230,6 +248,39 @@ function getStoreId(): number | string | null {
|
|
|
return localGet("geeker-user")?.userInfo?.storeId ?? localGet("createdId") ?? null;
|
|
return localGet("geeker-user")?.userInfo?.storeId ?? localGet("createdId") ?? null;
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
|
|
+function getTableRowsFromProTable(): CategoryRow[] {
|
|
|
|
|
+ const p = proTable.value as any;
|
|
|
|
|
+ const td = p?.tableData;
|
|
|
|
|
+ const list = td && typeof td === "object" && "value" in td ? td.value : td;
|
|
|
|
|
+ return Array.isArray(list) ? list : [];
|
|
|
|
|
+}
|
|
|
|
|
+
|
|
|
|
|
+/** 拖拽结束后按当前表格顺序保存(防抖,避免连续误触) */
|
|
|
|
|
+const persistSortOrder = useDebounceFn(async () => {
|
|
|
|
|
+ const storeId = getStoreId();
|
|
|
|
|
+ if (!storeId) return;
|
|
|
|
|
+ const rows = getTableRowsFromProTable();
|
|
|
|
|
+ const categoryIds = rows.map(r => r.id).filter(id => id != null && id !== "");
|
|
|
|
|
+ if (!categoryIds.length) return;
|
|
|
|
|
+ sortSaving.value = true;
|
|
|
|
|
+ try {
|
|
|
|
|
+ await scheduleSort({ categoryIds, storeId });
|
|
|
|
|
+ rows.forEach((row, i) => {
|
|
|
|
|
+ row._seq = i + 1;
|
|
|
|
|
+ });
|
|
|
|
|
+ ElMessage.success("排序已保存");
|
|
|
|
|
+ } catch (e: any) {
|
|
|
|
|
+ ElMessage.error(e?.message || "排序保存失败");
|
|
|
|
|
+ proTable.value?.getTableList();
|
|
|
|
|
+ } finally {
|
|
|
|
|
+ sortSaving.value = false;
|
|
|
|
|
+ }
|
|
|
|
|
+}, 400);
|
|
|
|
|
+
|
|
|
|
|
+function onDragSortEnd() {
|
|
|
|
|
+ persistSortOrder();
|
|
|
|
|
+}
|
|
|
|
|
+
|
|
|
/** 接口返回 true 表示该分类下桌号存在预定,不可编辑/删除 */
|
|
/** 接口返回 true 表示该分类下桌号存在预定,不可编辑/删除 */
|
|
|
function parseHasReservationResponse(res: any): boolean {
|
|
function parseHasReservationResponse(res: any): boolean {
|
|
|
const body = res?.data ?? res;
|
|
const body = res?.data ?? res;
|
|
@@ -395,6 +446,20 @@ async function submitForm() {
|
|
|
width: 100%;
|
|
width: 100%;
|
|
|
padding: 12px 0;
|
|
padding: 12px 0;
|
|
|
}
|
|
}
|
|
|
|
|
+.table-header-left {
|
|
|
|
|
+ display: flex;
|
|
|
|
|
+ flex-wrap: wrap;
|
|
|
|
|
+ gap: 12px;
|
|
|
|
|
+ align-items: center;
|
|
|
|
|
+}
|
|
|
|
|
+.sort-tip,
|
|
|
|
|
+.sort-saving-tip {
|
|
|
|
|
+ font-size: 12px;
|
|
|
|
|
+ color: #909399;
|
|
|
|
|
+}
|
|
|
|
|
+.sort-saving-tip {
|
|
|
|
|
+ color: #6c8ff8;
|
|
|
|
|
+}
|
|
|
.status-show {
|
|
.status-show {
|
|
|
color: #67c23a;
|
|
color: #67c23a;
|
|
|
}
|
|
}
|