update point rule groovy script
This commit is contained in:
+8
-1
@@ -6,7 +6,8 @@ import type {
|
||||
PointAdjustRequest,
|
||||
PointLedger,
|
||||
PointLedgerPage,
|
||||
PointRule
|
||||
PointRule,
|
||||
GroovyScript
|
||||
} from "@/types/Point";
|
||||
import { getCurrentStoreId, withCurrentStoreId, withCurrentStorePage } from "@/utils/store";
|
||||
|
||||
@@ -94,6 +95,11 @@ async function ruleDetail(id: string): Promise<PointRule> {
|
||||
});
|
||||
}
|
||||
|
||||
/** 查询积分规则可选的 Groovy 脚本。 */
|
||||
async function ruleScriptList(): Promise<GroovyScript[]> {
|
||||
return await axios.post(`${BASE_URI}/rule/script/list`);
|
||||
}
|
||||
|
||||
async function ruleCreate(rule: PointRule): Promise<string> {
|
||||
return await axios.post(`${BASE_URI}/rule/create`, withCurrentStoreId(rule));
|
||||
}
|
||||
@@ -120,6 +126,7 @@ export default {
|
||||
adjust,
|
||||
ruleList,
|
||||
ruleDetail,
|
||||
ruleScriptList,
|
||||
ruleCreate,
|
||||
ruleUpdate,
|
||||
ruleSort,
|
||||
|
||||
@@ -22,9 +22,6 @@
|
||||
borderless
|
||||
/>
|
||||
</t-form-item>
|
||||
<t-form-item v-if="isGlobalManager" label="门店" :arrow="isCreateMode" @click="openStorePicker">
|
||||
<div class="picker-text" v-text="selectedStoreName" />
|
||||
</t-form-item>
|
||||
<t-form-item label="业务类型" :arrow="false">
|
||||
<div class="picker-text" v-text="getBizTypeText(formModel.bizType)" />
|
||||
</t-form-item>
|
||||
@@ -171,15 +168,6 @@
|
||||
@confirm="confirmLimitPicker"
|
||||
/>
|
||||
</t-popup>
|
||||
<t-popup v-model="storePickerVisible" placement="bottom">
|
||||
<t-picker
|
||||
v-model="storePickerDraft"
|
||||
:columns="storePickerColumns"
|
||||
title="选择门店"
|
||||
@cancel="storePickerVisible = false"
|
||||
@confirm="confirmStorePicker"
|
||||
/>
|
||||
</t-popup>
|
||||
<t-popup v-model="statusPickerVisible" placement="bottom">
|
||||
<t-picker
|
||||
v-model="statusPickerDraft"
|
||||
@@ -311,46 +299,6 @@ function getBizTypeText(value: EventBizType): string {
|
||||
return getEventBizTypeText(value);
|
||||
}
|
||||
|
||||
// ---------- 门店选择 ----------
|
||||
|
||||
const storePickerVisible = ref(false);
|
||||
const storePickerDraft = ref<PickerValue[]>([]);
|
||||
const storePickerColumns = computed(() => [
|
||||
currentStoreStore.storeList
|
||||
.map(item => ({
|
||||
label: item.name || item.code || "未命名门店",
|
||||
value: item.id || ""
|
||||
}))
|
||||
.filter(item => item.value)
|
||||
]);
|
||||
const selectedStoreName = computed(() => {
|
||||
const store = currentStoreStore.storeList.find(item => item.id === formModel.storeId);
|
||||
return store?.name || store?.code || "请选择门店";
|
||||
});
|
||||
|
||||
function openStorePicker(): void {
|
||||
if (!isCreateMode.value) {
|
||||
return;
|
||||
}
|
||||
if (!currentStoreStore.storeList.length) {
|
||||
Message.warning("暂无可选门店");
|
||||
return;
|
||||
}
|
||||
|
||||
storePickerDraft.value = [formModel.storeId];
|
||||
storePickerVisible.value = true;
|
||||
}
|
||||
|
||||
async function confirmStorePicker(): Promise<void> {
|
||||
const storeId = String(storePickerDraft.value[0] || "");
|
||||
if (!storeId) {
|
||||
return;
|
||||
}
|
||||
|
||||
formModel.storeId = storeId;
|
||||
storePickerVisible.value = false;
|
||||
}
|
||||
|
||||
// ---------- 颜色 ----------
|
||||
|
||||
const colorPickerVisible = ref(false);
|
||||
@@ -600,7 +548,7 @@ function resolveTimestamp(valueText: string): number | undefined {
|
||||
|
||||
function validateForm(): boolean {
|
||||
if (!formModel.storeId) {
|
||||
Message.warning("请选择门店");
|
||||
Message.warning("当前门店不可用");
|
||||
return false;
|
||||
}
|
||||
if (!formModel.name.trim()) {
|
||||
@@ -729,15 +677,10 @@ async function saveEventItem(): Promise<void> {
|
||||
async function prepareStoreScope(): Promise<void> {
|
||||
if (isGlobalManager.value) {
|
||||
await currentStoreStore.loadStoreList();
|
||||
const queryStoreId = String(route.query.storeId || "");
|
||||
formModel.storeId = currentStoreStore.storeList.some(item => item.id === queryStoreId)
|
||||
? queryStoreId
|
||||
: currentStoreStore.currentStoreId;
|
||||
return;
|
||||
} else {
|
||||
await currentStoreStore.loadLoginStore();
|
||||
}
|
||||
|
||||
const store = await currentStoreStore.loadLoginStore();
|
||||
formModel.storeId = store?.id || "";
|
||||
formModel.storeId = currentStoreStore.currentStoreId;
|
||||
}
|
||||
|
||||
async function fillForm(): Promise<void> {
|
||||
|
||||
@@ -328,10 +328,7 @@ async function loadData(): Promise<void> {
|
||||
}
|
||||
|
||||
async function toCreate(): Promise<void> {
|
||||
await router.push({
|
||||
path: "/management/registration-events/create",
|
||||
query: currentStoreStore.currentStoreId ? { storeId: currentStoreStore.currentStoreId } : undefined
|
||||
});
|
||||
await router.push("/management/registration-events/create");
|
||||
}
|
||||
|
||||
async function toSort(): Promise<void> {
|
||||
|
||||
@@ -64,6 +64,7 @@
|
||||
<t-cell title="规则名称" :note="hitRule.name || '未命名规则'" />
|
||||
<t-cell title="规则模式" :note="hitRule.ruleMode === 'GROOVY' ? '脚本规则' : '简单规则'" />
|
||||
<t-cell title="规则积分" :note="getRulePointText(hitRule)" />
|
||||
<t-cell v-if="hitRule.ruleMode === 'GROOVY'" title="执行脚本" :note="getRuleScriptText(hitRule)" />
|
||||
<t-cell title="规则状态" :note="getRuleStatusText(hitRule.status)" />
|
||||
<t-cell title="规则优先级" :note="getPointText(hitRule.priority)" />
|
||||
<t-cell title="命中后停止匹配" :note="hitRule.exclusive ? '是' : '否'" />
|
||||
@@ -254,6 +255,15 @@ function getRulePointText(rule: PointRule): string {
|
||||
return `${0 < rule.pointValue ? "发放" : "消耗"} ${Math.abs(rule.pointValue)} 分`;
|
||||
}
|
||||
|
||||
function getRuleScriptText(rule: PointRule): string {
|
||||
const script = rule.groovyScript;
|
||||
if (!script) {
|
||||
return rule.groovyScriptId || "未绑定脚本";
|
||||
}
|
||||
const version = script.latest?.version;
|
||||
return `${script.name || script.code || "未命名脚本"}${version === undefined ? "" : `(v${version})`}`;
|
||||
}
|
||||
|
||||
function getRuleStatusText(status?: PointRuleStatus): string {
|
||||
return ({
|
||||
DRAFT: "草稿",
|
||||
|
||||
@@ -34,7 +34,27 @@
|
||||
<t-cell-group v-if="rule" title="积分配置" theme="card" v-entrance-transition="140">
|
||||
<t-cell title="规则模式" :note="rule.ruleMode === 'GROOVY' ? '脚本规则' : '简单规则'" />
|
||||
<t-cell v-if="rule.ruleMode !== 'GROOVY'" title="固定积分" :note="formatPointValue(rule.pointValue)" />
|
||||
<t-cell v-else title="执行脚本" :note="rule.groovyScriptId || '未绑定脚本'" />
|
||||
<template v-if="rule?.ruleMode === 'GROOVY'">
|
||||
<t-cell title="执行脚本" :note="scriptName" />
|
||||
<t-cell class="empty-cell-title-margin" title="脚本说明">
|
||||
<template #description>
|
||||
<markdown-view :content="rule.groovyScript?.description || '暂无脚本说明'" />
|
||||
</template>
|
||||
</t-cell>
|
||||
<t-cell class="empty-cell-title-margin" title="脚本代码">
|
||||
<template #description>
|
||||
<code-editor
|
||||
v-if="scriptContent"
|
||||
:value="scriptContent"
|
||||
language="groovy"
|
||||
readonly
|
||||
line-numbers
|
||||
class="script-editor"
|
||||
/>
|
||||
<div v-else class="empty-script" v-text="'暂无脚本代码'" />
|
||||
</template>
|
||||
</t-cell>
|
||||
</template>
|
||||
</t-cell-group>
|
||||
<t-cell-group v-if="rule" title="其他配置" theme="card" v-entrance-transition="280">
|
||||
<t-cell title="规则优先级" :note="formatNumber(rule.priority)" />
|
||||
@@ -60,7 +80,8 @@
|
||||
|
||||
<script setup lang="ts">
|
||||
import { DialogPlugin } from "tdesign-mobile-vue";
|
||||
import { Text, Time } from "timi-web";
|
||||
import { CodeEditor } from "timi-tdesign-mobile";
|
||||
import { MarkdownView, Text, Time } from "timi-web";
|
||||
import { useUserStore } from "timi-web-api";
|
||||
import EventAPI from "@/api/EventAPI";
|
||||
import PointAPI from "@/api/PointAPI";
|
||||
@@ -112,6 +133,22 @@ const rulePointText = computed(() => {
|
||||
}
|
||||
return formatPointValue(rule.value?.pointValue);
|
||||
});
|
||||
const scriptName = computed(() => rule.value?.groovyScript?.name || rule.value?.groovyScriptId || "未绑定脚本");
|
||||
const scriptStatusText = computed(() => {
|
||||
const script = rule.value?.groovyScript;
|
||||
if (!script) {
|
||||
return "脚本不存在";
|
||||
}
|
||||
if (script.enabled && script.publishedVersionId) {
|
||||
return "已启用并已发布";
|
||||
}
|
||||
return script.enabled ? "已启用,未发布" : "已停用";
|
||||
});
|
||||
const scriptVersionText = computed(() => {
|
||||
const version = rule.value?.groovyScript?.latest?.version;
|
||||
return version === undefined || version === null ? "未创建版本" : String(version);
|
||||
});
|
||||
const scriptContent = computed(() => rule.value?.groovyScript?.latest?.content || "");
|
||||
|
||||
async function loadStoreScope(): Promise<void> {
|
||||
if (isGlobalManager.value) {
|
||||
@@ -349,5 +386,22 @@ onUnmounted(() => {
|
||||
color: var(--td-text-color-secondary);
|
||||
}
|
||||
}
|
||||
|
||||
.script-section {
|
||||
|
||||
.script-editor {
|
||||
height: 24rem;
|
||||
min-height: 16rem;
|
||||
background: var(--td-bg-color-page);
|
||||
border-radius: .5rem;
|
||||
}
|
||||
|
||||
.empty-script {
|
||||
padding: 1rem;
|
||||
color: var(--td-text-color-placeholder);
|
||||
background: var(--td-bg-color-page);
|
||||
border-radius: .5rem;
|
||||
}
|
||||
}
|
||||
}
|
||||
</style>
|
||||
|
||||
@@ -2,9 +2,6 @@
|
||||
<div v-can="pageAccess" class="point-rule-edit">
|
||||
<t-form class="form" label-align="left" label-width="7rem">
|
||||
<card-container v-entrance-transition>
|
||||
<t-form-item v-if="isGlobalManager" label="门店" required-mark :arrow="isCreateMode" @click="openStorePicker">
|
||||
<span class="picker-text" v-text="selectedStoreName" />
|
||||
</t-form-item>
|
||||
<t-form-item label="触发来源" required-mark arrow @click="openTriggerSourcePicker">
|
||||
<span class="picker-text" v-text="getTriggerSourceText(formModel.triggerSourceType)" />
|
||||
</t-form-item>
|
||||
@@ -23,6 +20,15 @@
|
||||
</t-form-item>
|
||||
</card-container>
|
||||
<card-container v-entrance-transition="70">
|
||||
<t-form-item label="规则模式" arrow @click="openRuleModePicker">
|
||||
<span class="picker-text" v-text="getRuleModeText(formModel.ruleMode)" />
|
||||
</t-form-item>
|
||||
<template v-if="formModel.ruleMode === 'GROOVY'">
|
||||
<t-form-item label="执行脚本" required-mark arrow @click="openScriptPicker">
|
||||
<span class="picker-text" v-text="selectedScriptText" />
|
||||
</t-form-item>
|
||||
</template>
|
||||
<template v-else>
|
||||
<t-form-item label="积分动作" arrow @click="openPointActionPicker">
|
||||
<span class="picker-text" v-text="getPointActionText(formModel.pointAction)" />
|
||||
</t-form-item>
|
||||
@@ -35,6 +41,7 @@
|
||||
placeholder="请输入数量"
|
||||
/>
|
||||
</t-form-item>
|
||||
</template>
|
||||
</card-container>
|
||||
<card-container v-entrance-transition="140">
|
||||
<t-form-item label="生效开始" arrow @click="openBeginAtPicker">
|
||||
@@ -57,15 +64,6 @@
|
||||
</card-container>
|
||||
</t-form>
|
||||
</div>
|
||||
<t-popup v-model="storePickerVisible" placement="bottom">
|
||||
<t-picker
|
||||
v-model="storePickerDraft"
|
||||
:columns="storePickerColumns"
|
||||
title="选择门店"
|
||||
@cancel="storePickerVisible = false"
|
||||
@confirm="confirmStorePicker"
|
||||
/>
|
||||
</t-popup>
|
||||
<t-popup v-model="eventPickerVisible" placement="bottom">
|
||||
<t-picker
|
||||
v-model="eventPickerDraft"
|
||||
@@ -102,6 +100,51 @@
|
||||
@confirm="confirmPointActionPicker"
|
||||
/>
|
||||
</t-popup>
|
||||
<t-popup v-model="ruleModePickerVisible" placement="bottom">
|
||||
<t-picker
|
||||
v-model="ruleModePickerDraft"
|
||||
:columns="ruleModePickerColumns"
|
||||
title="规则模式"
|
||||
@cancel="ruleModePickerVisible = false"
|
||||
@confirm="confirmRuleModePicker"
|
||||
/>
|
||||
</t-popup>
|
||||
<bottom-popup
|
||||
v-model="scriptPickerVisible"
|
||||
title="选择执行脚本"
|
||||
height="min(80vh, 48rem)"
|
||||
@left-button-click="cancelScriptPicker"
|
||||
@right-button-click="confirmScriptPicker"
|
||||
>
|
||||
<t-collapse
|
||||
v-if="availableScriptList.length"
|
||||
v-model="expandedScriptIdList"
|
||||
class="script-collapse"
|
||||
:expand-mutex="true"
|
||||
>
|
||||
<t-collapse-panel
|
||||
v-for="script in availableScriptList"
|
||||
:key="getScriptId(script)"
|
||||
:value="getScriptId(script)"
|
||||
class="script-panel"
|
||||
placement="bottom"
|
||||
>
|
||||
<template #header>
|
||||
<t-checkbox
|
||||
:model-value="scriptPickerDraftId === getScriptId(script)"
|
||||
:label="getScriptName(script)"
|
||||
borderless
|
||||
@click.stop
|
||||
@change="selectScript(getScriptId(script))"
|
||||
/>
|
||||
</template>
|
||||
<div class="script-description">
|
||||
<markdown-view :content="script.description || '暂无脚本说明'" />
|
||||
</div>
|
||||
</t-collapse-panel>
|
||||
</t-collapse>
|
||||
<t-empty v-else description="暂无可选积分脚本" />
|
||||
</bottom-popup>
|
||||
<t-popup v-model="beginAtPickerVisible" placement="bottom">
|
||||
<t-date-time-picker
|
||||
v-model="beginAtDraftText"
|
||||
@@ -127,7 +170,8 @@
|
||||
</template>
|
||||
|
||||
<script setup lang="ts">
|
||||
import { Time } from "timi-web";
|
||||
import { BottomPopup } from "timi-tdesign-mobile";
|
||||
import { MarkdownView, Time } from "timi-web";
|
||||
import { useUserStore } from "timi-web-api";
|
||||
import EventAPI from "@/api/EventAPI";
|
||||
import PointAPI from "@/api/PointAPI";
|
||||
@@ -135,8 +179,10 @@ import { useCurrentStoreStore } from "@/store/currentStoreStore";
|
||||
import { useNavBarStore } from "@/store/navBarStore";
|
||||
import type { EventItem } from "@/types/EventItem";
|
||||
import type {
|
||||
GroovyScript,
|
||||
PointAction,
|
||||
PointRule,
|
||||
PointRuleMode,
|
||||
PointRuleStatus,
|
||||
PointRuleTriggerSourceType
|
||||
} from "@/types/Point";
|
||||
@@ -170,30 +216,24 @@ const isSaving = ref(false);
|
||||
const formModel = reactive({
|
||||
id: "",
|
||||
storeId: "",
|
||||
ruleMode: "SIMPLE" as PointRuleMode,
|
||||
triggerSourceType: "EVENT_RECORD" as PointRuleTriggerSourceType,
|
||||
triggerRefId: "",
|
||||
name: "",
|
||||
status: "DRAFT" as PointRuleStatus,
|
||||
pointAction: "EARN" as PointAction,
|
||||
pointValueText: "",
|
||||
groovyScriptId: "",
|
||||
beginAtText: "",
|
||||
endAtText: "",
|
||||
exclusive: false,
|
||||
remark: ""
|
||||
});
|
||||
|
||||
// ---------- 门店与事件 ----------
|
||||
// ---------- 事件与脚本 ----------
|
||||
|
||||
const eventList = ref<EventItem[]>([]);
|
||||
const selectedStoreName = computed(() => currentStoreStore.storeList.find(item => item.id === formModel.storeId)?.name || "请选择门店");
|
||||
const selectedEventName = computed(() => eventList.value.find(item => item.id === formModel.triggerRefId)?.name || "请选择触发事件");
|
||||
const storePickerVisible = ref(false);
|
||||
const storePickerDraft = ref<PickerValue[]>([]);
|
||||
const storePickerColumns = computed(() => [
|
||||
currentStoreStore.storeList
|
||||
.map(item => ({ label: item.name || item.code || "未命名门店", value: item.id || "" }))
|
||||
.filter(item => item.value)
|
||||
]);
|
||||
const eventPickerVisible = ref(false);
|
||||
const eventPickerDraft = ref<PickerValue[]>([]);
|
||||
const eventPickerColumns = computed(() => [
|
||||
@@ -202,28 +242,15 @@ const eventPickerColumns = computed(() => [
|
||||
.filter(item => item.value)
|
||||
]);
|
||||
|
||||
function openStorePicker(): void {
|
||||
if (!isCreateMode.value || !storePickerColumns.value[0]?.length) {
|
||||
return;
|
||||
const scriptList = ref<GroovyScript[]>([]);
|
||||
const selectedScript = computed(() => scriptList.value.find(item => item.id === formModel.groovyScriptId));
|
||||
const availableScriptList = computed(() => scriptList.value.filter(item => item.id));
|
||||
const selectedScriptText = computed(() => {
|
||||
if (!selectedScript.value) {
|
||||
return "请选择执行脚本";
|
||||
}
|
||||
storePickerDraft.value = [formModel.storeId];
|
||||
storePickerVisible.value = true;
|
||||
}
|
||||
|
||||
async function confirmStorePicker(value: Array<string | number>): Promise<void> {
|
||||
const storeId = String(value[0] || "");
|
||||
if (storeId && storeId !== formModel.storeId) {
|
||||
formModel.storeId = storeId;
|
||||
formModel.triggerRefId = "";
|
||||
try {
|
||||
await loadEventList();
|
||||
} catch {
|
||||
eventList.value = [];
|
||||
Message.error("触发事件加载失败");
|
||||
}
|
||||
}
|
||||
storePickerVisible.value = false;
|
||||
}
|
||||
return selectedScript.value.name || selectedScript.value.code || "未命名脚本";
|
||||
});
|
||||
|
||||
function openEventPicker(): void {
|
||||
if (!eventPickerColumns.value[0]?.length) {
|
||||
@@ -245,14 +272,10 @@ function confirmEventPicker(value: Array<string | number>): void {
|
||||
async function prepareStoreScope(): Promise<void> {
|
||||
if (isGlobalManager.value) {
|
||||
await currentStoreStore.loadStoreList();
|
||||
const queryStoreId = String(route.query.storeId || "");
|
||||
formModel.storeId = currentStoreStore.storeList.some(item => item.id === queryStoreId)
|
||||
? queryStoreId
|
||||
: currentStoreStore.currentStoreId;
|
||||
return;
|
||||
} else {
|
||||
await currentStoreStore.loadLoginStore();
|
||||
}
|
||||
const store = await currentStoreStore.loadLoginStore();
|
||||
formModel.storeId = store?.id || "";
|
||||
formModel.storeId = currentStoreStore.currentStoreId;
|
||||
}
|
||||
|
||||
async function loadEventList(): Promise<void> {
|
||||
@@ -265,6 +288,10 @@ async function loadEventList(): Promise<void> {
|
||||
}
|
||||
}
|
||||
|
||||
async function loadScriptList(): Promise<void> {
|
||||
scriptList.value = await PointAPI.ruleScriptList();
|
||||
}
|
||||
|
||||
// ---------- 规则选项 ----------
|
||||
|
||||
const statusOptions: Array<{ label: string; value: PointRuleStatus }> = [
|
||||
@@ -286,9 +313,27 @@ const pointActionOptions: Array<{ label: string; value: PointAction }> = [
|
||||
{ label: "发放积分", value: "EARN" },
|
||||
{ label: "消耗积分", value: "CONSUME" }
|
||||
];
|
||||
const ruleModeOptions: Array<{ label: string; value: PointRuleMode }> = [
|
||||
{ label: "简单规则", value: "SIMPLE" },
|
||||
{ label: "脚本规则", value: "GROOVY" }
|
||||
];
|
||||
const pointActionPickerVisible = ref(false);
|
||||
const pointActionPickerDraft = ref<PickerValue[]>([]);
|
||||
const pointActionPickerColumns = [pointActionOptions];
|
||||
const ruleModePickerVisible = ref(false);
|
||||
const ruleModePickerDraft = ref<PickerValue[]>([]);
|
||||
const ruleModePickerColumns = [ruleModeOptions];
|
||||
const scriptPickerVisible = ref(false);
|
||||
const scriptPickerDraftId = ref("");
|
||||
const expandedScriptIdList = ref<Array<string | number>>([]);
|
||||
|
||||
function getScriptId(script: GroovyScript): string {
|
||||
return script.id || "";
|
||||
}
|
||||
|
||||
function getScriptName(script: GroovyScript): string {
|
||||
return script.name || script.code || "未命名脚本";
|
||||
}
|
||||
|
||||
function openStatusPicker(): void {
|
||||
statusPickerDraft.value = [formModel.status];
|
||||
@@ -332,6 +377,52 @@ function confirmPointActionPicker(value: Array<string | number>): void {
|
||||
pointActionPickerVisible.value = false;
|
||||
}
|
||||
|
||||
function openRuleModePicker(): void {
|
||||
ruleModePickerDraft.value = [formModel.ruleMode];
|
||||
ruleModePickerVisible.value = true;
|
||||
}
|
||||
|
||||
function confirmRuleModePicker(value: Array<string | number>): void {
|
||||
const ruleMode = value[0];
|
||||
if (ruleMode !== "SIMPLE" && ruleMode !== "GROOVY") {
|
||||
return;
|
||||
}
|
||||
formModel.ruleMode = ruleMode;
|
||||
if (ruleMode === "SIMPLE") {
|
||||
formModel.groovyScriptId = "";
|
||||
} else {
|
||||
formModel.pointValueText = "";
|
||||
}
|
||||
ruleModePickerVisible.value = false;
|
||||
}
|
||||
|
||||
function openScriptPicker(): void {
|
||||
if (!availableScriptList.value.length) {
|
||||
Message.warning("暂无可选积分脚本");
|
||||
return;
|
||||
}
|
||||
scriptPickerDraftId.value = formModel.groovyScriptId;
|
||||
expandedScriptIdList.value = formModel.groovyScriptId ? [formModel.groovyScriptId] : [];
|
||||
scriptPickerVisible.value = true;
|
||||
}
|
||||
|
||||
function selectScript(scriptId: string): void {
|
||||
if (scriptId && availableScriptList.value.some(item => item.id === scriptId)) {
|
||||
scriptPickerDraftId.value = scriptId;
|
||||
}
|
||||
}
|
||||
|
||||
function cancelScriptPicker(): void {
|
||||
scriptPickerVisible.value = false;
|
||||
}
|
||||
|
||||
function confirmScriptPicker(): void {
|
||||
if (scriptPickerDraftId.value && availableScriptList.value.some(item => item.id === scriptPickerDraftId.value)) {
|
||||
formModel.groovyScriptId = scriptPickerDraftId.value;
|
||||
}
|
||||
scriptPickerVisible.value = false;
|
||||
}
|
||||
|
||||
function getStatusText(status: PointRuleStatus): string {
|
||||
return statusOptions.find(item => item.value === status)?.label || "草稿";
|
||||
}
|
||||
@@ -344,6 +435,10 @@ function getPointActionText(action: PointAction): string {
|
||||
return action === "CONSUME" ? "消耗积分" : "发放积分";
|
||||
}
|
||||
|
||||
function getRuleModeText(ruleMode: PointRuleMode): string {
|
||||
return ruleMode === "GROOVY" ? "脚本规则" : "简单规则";
|
||||
}
|
||||
|
||||
// ---------- 生效时间 ----------
|
||||
|
||||
const minimumDateTimeText = "1970-01-01 00:00";
|
||||
@@ -405,7 +500,7 @@ function resolveTimestamp(value: string): number | undefined {
|
||||
|
||||
function validateForm(): boolean {
|
||||
if (!formModel.storeId) {
|
||||
Message.warning("请选择门店");
|
||||
Message.warning("当前门店不可用");
|
||||
return false;
|
||||
}
|
||||
if (!formModel.name.trim()) {
|
||||
@@ -416,7 +511,12 @@ function validateForm(): boolean {
|
||||
Message.warning("请选择触发事件");
|
||||
return false;
|
||||
}
|
||||
if (!resolvePositiveInteger(formModel.pointValueText)) {
|
||||
if (formModel.ruleMode === "GROOVY") {
|
||||
if (!formModel.groovyScriptId) {
|
||||
Message.warning("请选择执行脚本");
|
||||
return false;
|
||||
}
|
||||
} else if (!resolvePositiveInteger(formModel.pointValueText)) {
|
||||
Message.warning("积分数量必须是正整数");
|
||||
return false;
|
||||
}
|
||||
@@ -438,14 +538,14 @@ async function saveRule(): Promise<void> {
|
||||
const payload: PointRule = {
|
||||
id: formModel.id || undefined,
|
||||
storeId: formModel.storeId,
|
||||
ruleMode: "SIMPLE",
|
||||
ruleMode: formModel.ruleMode,
|
||||
triggerSourceType: formModel.triggerSourceType,
|
||||
triggerRefType: formModel.triggerSourceType === "EVENT_RECORD" ? "EVENT" : undefined,
|
||||
triggerRefId: formModel.triggerSourceType === "EVENT_RECORD" ? formModel.triggerRefId : undefined,
|
||||
name: formModel.name.trim(),
|
||||
status: formModel.status,
|
||||
pointValue: resolvePointValue() ?? null,
|
||||
groovyScriptId: undefined,
|
||||
pointValue: formModel.ruleMode === "SIMPLE" ? resolvePointValue() ?? null : null,
|
||||
groovyScriptId: formModel.ruleMode === "GROOVY" ? formModel.groovyScriptId : undefined,
|
||||
beginAt: resolveTimestamp(formModel.beginAtText),
|
||||
endAt: resolveTimestamp(formModel.endAtText),
|
||||
exclusive: formModel.exclusive,
|
||||
@@ -469,17 +569,23 @@ async function saveRule(): Promise<void> {
|
||||
|
||||
async function fillForm(): Promise<void> {
|
||||
await prepareStoreScope();
|
||||
await loadScriptList();
|
||||
if (!isCreateMode.value) {
|
||||
const current = await PointAPI.ruleDetail(routeId.value);
|
||||
if (current.groovyScript?.id && !scriptList.value.some(item => item.id === current.groovyScript?.id)) {
|
||||
scriptList.value.push(current.groovyScript);
|
||||
}
|
||||
Object.assign(formModel, {
|
||||
id: current.id || "",
|
||||
storeId: current.storeId || formModel.storeId,
|
||||
ruleMode: current.ruleMode || "SIMPLE",
|
||||
triggerSourceType: current.triggerSourceType || "EVENT_RECORD",
|
||||
triggerRefId: current.triggerRefId || "",
|
||||
name: current.name || "",
|
||||
status: current.status === "ACTIVE" ? "ACTIVE" : current.status === "INACTIVE" ? "INACTIVE" : "DRAFT",
|
||||
pointAction: current.pointValue !== undefined && current.pointValue !== null && current.pointValue < 0 ? "CONSUME" : "EARN",
|
||||
pointValueText: current.pointValue === undefined || current.pointValue === null ? "" : String(Math.abs(current.pointValue)),
|
||||
groovyScriptId: current.groovyScriptId || "",
|
||||
beginAtText: current.beginAt ? Time.toDateTime(current.beginAt) : "",
|
||||
endAtText: current.endAt ? Time.toDateTime(current.endAt) : "",
|
||||
exclusive: current.exclusive ?? false,
|
||||
@@ -543,6 +649,13 @@ onUnmounted(() => navBarStore.clearRight());
|
||||
}
|
||||
}
|
||||
|
||||
.script-collapse {
|
||||
|
||||
:deep(.t-cell) {
|
||||
padding: 0 10px;
|
||||
}
|
||||
}
|
||||
|
||||
:global(html.theme-dark) {
|
||||
.point-rule-edit {
|
||||
.form {
|
||||
@@ -554,6 +667,10 @@ onUnmounted(() => navBarStore.clearRight());
|
||||
color: #94a3b8;
|
||||
}
|
||||
}
|
||||
|
||||
.script-description {
|
||||
color: #94a3b8;
|
||||
}
|
||||
}
|
||||
}
|
||||
</style>
|
||||
|
||||
@@ -264,10 +264,7 @@ function getStatusTheme(status?: PointRuleStatus): "default" | "success" | "warn
|
||||
}
|
||||
|
||||
async function toCreate(): Promise<void> {
|
||||
await router.push({
|
||||
name: "PointRuleCreate",
|
||||
query: currentStoreStore.currentStoreId ? { storeId: currentStoreStore.currentStoreId } : undefined
|
||||
});
|
||||
await router.push({ name: "PointRuleCreate" });
|
||||
}
|
||||
|
||||
async function toSort(): Promise<void> {
|
||||
|
||||
@@ -12,6 +12,23 @@ export type PointRuleTriggerSourceType = "EVENT_RECORD" | "SALES_ORDER_PAID";
|
||||
/** 触发对象筛选类型 */
|
||||
export type PointRuleTriggerRefType = "EVENT";
|
||||
|
||||
export type GroovyScript = {
|
||||
bizType?: "GAO_POINT_RULE";
|
||||
code?: string;
|
||||
name?: string;
|
||||
description?: string;
|
||||
enabled?: boolean;
|
||||
publishedVersionId?: string;
|
||||
latest?: GroovyScriptVersion | null;
|
||||
} & Model;
|
||||
|
||||
export type GroovyScriptVersion = {
|
||||
scriptId?: string;
|
||||
version?: number;
|
||||
content?: string;
|
||||
checksum?: string;
|
||||
} & Model;
|
||||
|
||||
export type PointLedgerChangeType = "EARN" | "CONSUME" | "REVOKE" | "ADJUST";
|
||||
export type PointLedgerDirection = "INCREASE" | "DECREASE";
|
||||
export type PointAction = Extract<PointLedgerChangeType, "EARN" | "CONSUME">;
|
||||
@@ -81,6 +98,7 @@ export type PointRule = {
|
||||
priority?: number;
|
||||
exclusive?: boolean;
|
||||
remark?: string;
|
||||
groovyScript?: GroovyScript | null;
|
||||
} & Model;
|
||||
|
||||
export type PointAdjustRequest = {
|
||||
|
||||
Reference in New Issue
Block a user