Files
gao-customer-h5/src/pages/store/StoreEdit.vue
T
2026-08-26 21:18:02 +08:00

334 lines
8.0 KiB
Vue
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
<template>
<div v-can="savePermissionCode" class="store-edit">
<t-form class="form" label-align="left" v-entrance-transition>
<t-form-item v-if="!isStoreManagerScope" label="编码">
<t-input v-model.trim="formData.code" placeholder="门店编码" borderless />
</t-form-item>
<t-form-item label="名称">
<t-input v-model.trim="formData.name" placeholder="门店名称" borderless />
</t-form-item>
<t-form-item v-if="!isStoreManagerScope" label="启用" content-align="right">
<t-switch v-model="formData.status" :custom-value="['ACTIVE', 'INACTIVE']" />
</t-form-item>
<t-form-item label="电话">
<t-input v-model.trim="formData.telephone" type="tel" placeholder="联系电话" borderless />
</t-form-item>
<t-form-item label="地址">
<t-input v-model.trim="formData.address" placeholder="门店地址" borderless />
</t-form-item>
<t-form-item label="备注">
<t-textarea v-model.trim="formData.remark" class="textarea" placeholder="备注" autosize borderless />
</t-form-item>
</t-form>
<t-cell-group v-if="!isCreateMode" theme="card" v-entrance-transition="70">
<t-cell
title="营业日管理"
note="配置营业或休息日期"
arrow
@click="router.push(`/management/stores/${routeId}/business-days`)"
/>
<t-cell
title="自动休息日"
description="全天无任何登记记录时自动判定为休息日,休息日不视为中断连续登记事件"
>
<template #right-icon>
<t-switch v-model="formData.autoClosedDay" />
</template>
</t-cell>
</t-cell-group>
<div v-if="!isCreateMode && !isStoreManagerScope" class="actions" v-entrance-transition="140">
<t-button
v-can="permissionCodes.store.delete"
class="action"
theme="danger"
:loading="isRemoving"
@click="confirmRemoveStore"
>删除</t-button>
</div>
<t-dialog
class="remove-dialog"
v-model:visible="removeDialogVisible"
title="删除门店"
>
<div class="content">
<div class="warning">删除后将同步处理以下数据:</div>
<ul class="items">
<li>删除该门店下的所有客户</li>
<li>删除客户的登记记录及相关附件</li>
<li>删除积分规则和积分账户</li>
<li>删除登记事件及事件角色关联</li>
<li>删除门店营业日数据</li>
<li>删除门店用户关系</li>
<li>删除门店自有标签</li>
</ul>
<div class="warning">特别说明:</div>
<ul class="items">
<li>已产生的积分流水不会删除,将保留积分撤销记录</li>
<li>关联的系统用户账号不会删除</li>
<li>删除后无法恢复,请谨慎操作</li>
</ul>
<div class="hint">
请输入门店名称
<span class="name red" v-text="removeStoreName" />
以确认删除
</div>
<t-input
class="confirm-input"
v-model.trim="removeConfirmName"
size="small"
borderless
clearable
placeholder="请输入门店名称"
/>
</div>
<template #cancelBtn>
<t-button
theme="default"
content="取消"
block
@click="closeRemoveDialog"
/>
</template>
<template #confirmBtn>
<t-button
theme="danger"
content="删除"
block
:disabled="!canConfirmRemove"
@click="removeConfirmedStore"
/>
</template>
</t-dialog>
</div>
</template>
<script setup lang="ts">
import { useUserStore } from "timi-web-api";
import StoreAPI from "@/api/StoreAPI";
import { useCurrentStoreStore } from "@/store/currentStoreStore";
import { useNavBarStore } from "@/store/navBarStore";
import type { StoreStatus } from "@/types/Store";
import { gaoRoleCodes, permissionCodes } from "@/utils/permission";
import { Message } from "@/utils/message.ts";
defineOptions({
name: "StoreEdit"
});
const route = useRoute();
const router = useRouter();
const navBarStore = useNavBarStore();
const userStore = useUserStore();
const currentStoreStore = useCurrentStoreStore();
const routeId = computed(() => String(route.params.id || ""));
const isStoreManagerScope = computed(() => userStore.hasRoles(gaoRoleCodes.storeManager) && !userStore.hasRoles(gaoRoleCodes.globalManager));
// ---------- 路由权限 ----------
const isCreateMode = computed(() => !routeId.value);
const savePermissionCode = computed(() => isCreateMode.value ? permissionCodes.store.create : permissionCodes.store.update);
// ---------- 表单 ----------
const isSaving = ref(false);
const isRemoving = ref(false);
const removeDialogVisible = ref(false);
const removeConfirmName = ref("");
const formData = reactive({
id: "",
code: "",
name: "",
status: "ACTIVE" as StoreStatus,
telephone: "",
address: "",
remark: "",
autoClosedDay: true
});
const removeStoreName = computed(() => formData.name);
const canConfirmRemove = computed(() => !!removeStoreName.value && removeConfirmName.value === removeStoreName.value);
async function doSave(): Promise<void> {
if (!validateForm()) {
return;
}
isSaving.value = true;
try {
if (isCreateMode.value) {
await StoreAPI.create(formData);
} else {
await StoreAPI.update(formData);
await refreshCurrentStore();
}
Message.success("门店已保存");
if (userStore.hasPermissions(permissionCodes.store.create)) {
await router.replace("/management/stores");
} else {
await router.replace("/store");
}
} finally {
isSaving.value = false;
}
}
async function refreshCurrentStore(): Promise<void> {
if (formData.id !== currentStoreStore.currentStoreId) {
return;
}
await currentStoreStore.refreshCurrentStore(formData.id);
}
function validateForm(): boolean {
if (!isStoreManagerScope.value && !formData.code) {
Message.warning("请填写门店编码");
return false;
}
if (!formData.name) {
Message.warning("请填写门店名称");
return false;
}
return true;
}
onMounted(async () => {
if (userStore.hasPermissions(savePermissionCode.value)) {
navBarStore.setRightText("保存", "var(--td-brand-color)", doSave);
}
try {
if (!routeId.value) {
return;
}
const current = await StoreAPI.detail(routeId.value);
Object.assign(formData, current);
} catch {
Message.error("门店数据加载失败");
}
});
onUnmounted(() => navBarStore.clearRight());
// ---------- 删除 ----------
async function confirmRemoveStore(): Promise<void> {
if (!formData.id || isRemoving.value) {
return;
}
removeConfirmName.value = "";
removeDialogVisible.value = true;
}
function closeRemoveDialog(): void {
removeDialogVisible.value = false;
removeConfirmName.value = "";
}
async function removeConfirmedStore(): Promise<void> {
if (!formData.id || !canConfirmRemove.value || isRemoving.value) {
return;
}
closeRemoveDialog();
await removeStore();
}
async function removeStore(): Promise<void> {
if (isRemoving.value) {
return;
}
isRemoving.value = true;
try {
await StoreAPI.remove(formData.id);
Message.success("门店已删除");
await router.replace("/management/stores");
} finally {
isRemoving.value = false;
}
}
</script>
<style scoped lang="less">
.store-edit {
gap: 1rem;
padding: calc(var(--app-nav-height) + 1rem) 0 calc(1rem + env(safe-area-inset-bottom, 0)) 0;
display: flex;
flex-direction: column;
.form {
border-radius: .75rem;
}
.textarea {
width: 100%;
}
.links {
margin: 1rem 0;
}
.actions {
margin: 0 1rem;
display: flex;
.action {
flex: 1;
}
}
}
.remove-dialog {
:deep(.t-dialog__footer) {
gap: 1rem;
}
.content {
text-align: left;
.warning {
color: #b42318;
font-weight: 700;
}
.items {
margin: .25rem 0 1rem;
display: flex;
max-height: 5rem;
overflow-y: auto;
line-height: 1.2;
padding-left: 1.25rem;
flex-direction: column;
}
.name {
font-weight: 700;
}
.confirm-input {
--td-input-vertical-padding: 10px;
border: 1px solid var(--td-component-border);
margin-top: .5rem;
border-radius: .75rem;
}
}
}
:global(html.theme-dark) {
.store-edit {
.remove-dialog {
.warning {
color: #fda29b;
}
.confirm-input {
background: rgba(15, 23, 42, .72);
border-color: rgba(148, 163, 184, .16);
}
}
}
}
</style>