add point rule sort
This commit is contained in:
@@ -83,9 +83,6 @@
|
||||
</t-form-item>
|
||||
</card-container>
|
||||
<card-container tips="命中规则并执行积分动作后不再匹配后续规则">
|
||||
<t-form-item label="优先级" required-mark>
|
||||
<t-input v-model.trim="formModel.priorityText" type="number" align="right" borderless placeholder="数值越小越优先" />
|
||||
</t-form-item>
|
||||
<t-form-item label="独占匹配" content-align="right">
|
||||
<t-switch size="small" v-model="formModel.exclusive" />
|
||||
</t-form-item>
|
||||
@@ -248,7 +245,6 @@ const formModel = reactive({
|
||||
tiers: [] as PointRuleTierForm[],
|
||||
beginAtText: "",
|
||||
endAtText: "",
|
||||
priorityText: "0",
|
||||
exclusive: false,
|
||||
remark: ""
|
||||
});
|
||||
@@ -696,11 +692,6 @@ function validateForm(): boolean {
|
||||
Toast.warning("生效结束时间不能早于开始时间");
|
||||
return false;
|
||||
}
|
||||
const priority = Number(formModel.priorityText);
|
||||
if (!Number.isSafeInteger(priority) || 0 > priority) {
|
||||
Toast.warning("优先级必须是大于等于 0 的整数");
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
@@ -722,7 +713,6 @@ async function saveRule(): Promise<void> {
|
||||
conditionJson: buildCondition(),
|
||||
beginAt: resolveTimestamp(formModel.beginAtText),
|
||||
endAt: resolveTimestamp(formModel.endAtText),
|
||||
priority: Number(formModel.priorityText),
|
||||
exclusive: formModel.exclusive,
|
||||
remark: formModel.remark.trim()
|
||||
};
|
||||
@@ -803,7 +793,6 @@ async function fillForm(): Promise<void> {
|
||||
tiers: [],
|
||||
beginAtText: current.beginAt ? Time.toDateTime(current.beginAt) : "",
|
||||
endAtText: current.endAt ? Time.toDateTime(current.endAt) : "",
|
||||
priorityText: String(current.priority ?? 0),
|
||||
exclusive: current.exclusive ?? false,
|
||||
remark: current.remark || ""
|
||||
});
|
||||
|
||||
@@ -73,6 +73,7 @@ import { type DropdownValue, Toast } from "tdesign-mobile-vue";
|
||||
import EventAPI from "@/api/EventAPI";
|
||||
import PointAPI from "@/api/PointAPI";
|
||||
import { useCurrentStoreStore } from "@/store/currentStoreStore";
|
||||
import { useNavBarStore } from "@/store/navBarStore";
|
||||
import type { EventItem } from "@/types/EventItem";
|
||||
import type { PointRule, PointRuleStatus } from "@/types/Point";
|
||||
import { gaoRoleCodes, permissionCodes } from "@/utils/permission";
|
||||
@@ -85,6 +86,7 @@ defineOptions({
|
||||
});
|
||||
|
||||
const router = useRouter();
|
||||
const navBarStore = useNavBarStore();
|
||||
const userStore = useUserStore();
|
||||
const currentStoreStore = useCurrentStoreStore();
|
||||
|
||||
@@ -297,12 +299,20 @@ async function preparePage(): Promise<void> {
|
||||
}
|
||||
|
||||
onMounted(async () => {
|
||||
navBarStore.clearRight();
|
||||
if (userStore.hasPermissions(permissionCodes.pointRule.update)) {
|
||||
navBarStore.setRightText("排序", "var(--td-brand-color)", () => {
|
||||
router.push("/management/points/rules/sort");
|
||||
});
|
||||
}
|
||||
try {
|
||||
await preparePage();
|
||||
} catch {
|
||||
Toast.error("积分规则页面加载失败");
|
||||
}
|
||||
});
|
||||
|
||||
onUnmounted(() => navBarStore.clearRight());
|
||||
</script>
|
||||
|
||||
<style scoped lang="less">
|
||||
|
||||
@@ -0,0 +1,161 @@
|
||||
<template>
|
||||
<div v-can="permissionCodes.pointRule.update" class="point-rule-sort">
|
||||
<div class="tip" v-text="'按住右侧拖动手柄调整规则顺序,保存后生效;仅显示启用规则'" />
|
||||
<div class="items">
|
||||
<t-cell-group v-if="ruleList.length" theme="card">
|
||||
<vue-draggable-next
|
||||
v-model="ruleList"
|
||||
class="draggable"
|
||||
item-key="id"
|
||||
handle=".handle"
|
||||
ghost-class="ghost"
|
||||
chosen-class="chosen"
|
||||
drag-class="dragging"
|
||||
:animation="180"
|
||||
:disabled="isLoading || isSaving"
|
||||
@change="sortDirty = true"
|
||||
>
|
||||
<t-cell v-for="item in ruleList" :key="item.id" class="cell">
|
||||
<template #title>
|
||||
<div class="title" v-text="item.name || '未命名规则'" />
|
||||
</template>
|
||||
<template #description>
|
||||
<div class="description">
|
||||
<span v-text="'积分值:' + getPointText(item)" />
|
||||
<span v-text="'登记事件:' + (eventNameMap.get(item.eventId || '') || '未绑定事件')" />
|
||||
</div>
|
||||
</template>
|
||||
<template #note>
|
||||
<t-tag :theme="item.exclusive ? 'warning' : 'default'" variant="outline" :content="item.exclusive ? '独占匹配' : '继续匹配'" />
|
||||
</template>
|
||||
<template #rightIcon>
|
||||
<t-icon class="handle" role="button" name="move" aria-label="拖动排序" />
|
||||
</template>
|
||||
</t-cell>
|
||||
</vue-draggable-next>
|
||||
</t-cell-group>
|
||||
<div v-else class="empty-block" v-text="isLoading ? '正在加载启用规则' : '暂无启用规则'" />
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script setup lang="ts">
|
||||
import { Toast } from "tdesign-mobile-vue";
|
||||
import { VueDraggableNext } from "vue-draggable-next";
|
||||
import EventAPI from "@/api/EventAPI";
|
||||
import PointAPI from "@/api/PointAPI";
|
||||
import { useNavBarStore } from "@/store/navBarStore";
|
||||
import type { EventItem } from "@/types/EventItem";
|
||||
import type { PointRule } from "@/types/Point";
|
||||
import { permissionCodes } from "@/utils/permission";
|
||||
|
||||
defineOptions({ name: "PointRuleSort" });
|
||||
|
||||
const navBarStore = useNavBarStore();
|
||||
const router = useRouter();
|
||||
const ruleList = ref<PointRule[]>([]);
|
||||
const eventList = ref<EventItem[]>([]);
|
||||
const isLoading = ref(false);
|
||||
const isSaving = ref(false);
|
||||
const sortDirty = ref(false);
|
||||
const eventNameMap = computed(() => new Map(eventList.value.filter(item => item.id).map(item => [item.id as string, item.name])));
|
||||
|
||||
function getPointText(rule: PointRule): string {
|
||||
if (rule.pointMode === "TIER") {
|
||||
return "分档";
|
||||
}
|
||||
if (rule.pointValue === undefined || rule.pointValue === null) {
|
||||
return "按登记值";
|
||||
}
|
||||
return (0 < rule.pointValue ? "+" : "") + rule.pointValue;
|
||||
}
|
||||
|
||||
async function loadData(): Promise<void> {
|
||||
isLoading.value = true;
|
||||
try {
|
||||
const [ruleResult, eventResult] = await Promise.all([
|
||||
PointAPI.ruleList({ index: 0, size: 1000, equalsExample: { status: "ACTIVE" } }),
|
||||
EventAPI.list({ index: 0, size: 1000 })
|
||||
]);
|
||||
ruleList.value = ruleResult.list || [];
|
||||
eventList.value = eventResult.list || [];
|
||||
sortDirty.value = false;
|
||||
} finally {
|
||||
isLoading.value = false;
|
||||
}
|
||||
}
|
||||
|
||||
async function saveSort(): Promise<void> {
|
||||
if (!sortDirty.value || isSaving.value) {
|
||||
return;
|
||||
}
|
||||
isSaving.value = true;
|
||||
try {
|
||||
const idList = ruleList.value.map(item => item.id).filter((id): id is string => Boolean(id));
|
||||
await PointAPI.ruleSort(idList);
|
||||
ruleList.value.forEach((item, index) => { item.priority = index; });
|
||||
sortDirty.value = false;
|
||||
Toast.success("积分规则排序已保存");
|
||||
await router.back();
|
||||
} catch {
|
||||
Toast.error("积分规则排序保存失败");
|
||||
} finally {
|
||||
isSaving.value = false;
|
||||
}
|
||||
}
|
||||
|
||||
onMounted(async () => {
|
||||
navBarStore.clearRight();
|
||||
navBarStore.setRightText("保存", "var(--td-brand-color)", saveSort);
|
||||
try {
|
||||
await loadData();
|
||||
} catch {
|
||||
Toast.error("启用积分规则加载失败");
|
||||
}
|
||||
});
|
||||
|
||||
onUnmounted(() => navBarStore.clearRight());
|
||||
</script>
|
||||
|
||||
<style scoped lang="less">
|
||||
.point-rule-sort {
|
||||
padding: calc(var(--app-nav-height) + 1rem) 0 6rem;
|
||||
|
||||
.tip,
|
||||
.empty-block {
|
||||
color: #52607a;
|
||||
padding: 0 1rem .75rem;
|
||||
font-size: .8125rem;
|
||||
}
|
||||
|
||||
.empty-block {
|
||||
padding-top: 2rem;
|
||||
text-align: center;
|
||||
}
|
||||
|
||||
.draggable {
|
||||
.cell {
|
||||
.title { font-weight: 600; }
|
||||
.description {
|
||||
display: flex;
|
||||
gap: .75rem;
|
||||
font-size: .75rem;
|
||||
}
|
||||
.handle { color: #52607a; cursor: grab; touch-action: none; }
|
||||
}
|
||||
.ghost { opacity: .4; }
|
||||
.chosen,
|
||||
.dragging { z-index: 1; box-shadow: 0 .5rem 1rem rgba(15, 23, 42, .16); }
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
:global(html.theme-dark) {
|
||||
.point-rule-sort {
|
||||
.tip,
|
||||
.empty-block,
|
||||
.handle { color: #94a3b8; }
|
||||
.draggable .cell { background: rgba(15, 23, 42, .88); }
|
||||
}
|
||||
}
|
||||
</style>
|
||||
Reference in New Issue
Block a user