diff --git a/.gitignore b/.gitignore index 6d1f72a..d30198a 100644 --- a/.gitignore +++ b/.gitignore @@ -1,4 +1,5 @@ node_modules +.pnpm-store/ .DS_Store dist dist-ssr diff --git a/.husky/commit-msg b/.husky/commit-msg index 09d2b14..28e67e9 100644 --- a/.husky/commit-msg +++ b/.husky/commit-msg @@ -1 +1,6 @@ -pnpm dlx commitlint --edit $1 \ No newline at end of file +if [ ! -w "${HOME:-/root}" ]; then + export XDG_CACHE_HOME="${XDG_CACHE_HOME:-/tmp}" + export COREPACK_HOME="${COREPACK_HOME:-/tmp/corepack}" +fi + +corepack pnpm dlx commitlint --edit "$1" diff --git a/.husky/pre-commit b/.husky/pre-commit index 22c0347..882a730 100644 --- a/.husky/pre-commit +++ b/.husky/pre-commit @@ -1 +1,6 @@ -pnpm run lint:lint-staged \ No newline at end of file +if [ ! -w "${HOME:-/root}" ]; then + export XDG_CACHE_HOME="${XDG_CACHE_HOME:-/tmp}" + export COREPACK_HOME="${COREPACK_HOME:-/tmp/corepack}" +fi + +corepack pnpm run lint:lint-staged diff --git a/eslint.config.mjs b/eslint.config.mjs index bb317f6..7f126fe 100644 --- a/eslint.config.mjs +++ b/eslint.config.mjs @@ -15,9 +15,15 @@ const __filename = fileURLToPath(import.meta.url) const __dirname = dirname(__filename) // 读取 .auto-import.json 文件的内容,并将其解析为 JSON 对象 -const autoImportConfig = JSON.parse( - fs.readFileSync(path.resolve(__dirname, '.auto-import.json'), 'utf-8') -) +// 说明:该文件由 unplugin-auto-import 在 Vite 启动时生成,首次安装依赖后可能尚未生成 +let autoImportConfig = { globals: {} } +try { + autoImportConfig = JSON.parse( + fs.readFileSync(path.resolve(__dirname, '.auto-import.json'), 'utf-8') + ) +} catch { + autoImportConfig = { globals: {} } +} export default [ // 指定文件匹配规则 diff --git a/pnpm-workspace.yaml b/pnpm-workspace.yaml index 4226ea1..59ec233 100644 --- a/pnpm-workspace.yaml +++ b/pnpm-workspace.yaml @@ -1,3 +1,6 @@ +packages: + - . + onlyBuiltDependencies: - '@parcel/watcher' - '@tailwindcss/oxide' diff --git a/src/api/tenant-onboarding.ts b/src/api/tenant-onboarding.ts deleted file mode 100644 index 9ab68f7..0000000 --- a/src/api/tenant-onboarding.ts +++ /dev/null @@ -1,99 +0,0 @@ -import request from '@/utils/http' - -/** - * 自助注册租户 - * @param data 自助注册参数 - */ -export function fetchSelfRegisterTenant(data: Api.Tenant.SelfRegisterTenantCommand) { - return request.post({ - url: '/api/public/v1/tenants/self-register', - data - }) -} - -/** - * 查询租户入驻进度 - * @param tenantId 租户ID - */ -export function fetchTenantProgress(tenantId: string) { - return request.get({ - url: `/api/public/v1/tenants/${tenantId}/status` - }) -} - -/** - * 提交或更新租户实名信息 - * @param tenantId 租户ID - * @param data 实名资料 - */ -export function submitTenantVerification( - tenantId: string, - data: Api.Tenant.SubmitTenantVerificationCommand -) { - return request.post({ - url: `/api/public/v1/tenants/${tenantId}/verification`, - data: { ...data, tenantId } - }) -} - -/** - * 提交或更新租户实名信息(管理端) - * @param tenantId 租户ID - * @param data 实名资料 - */ -export function submitTenantVerificationAdmin( - tenantId: string, - data: Api.Tenant.SubmitTenantVerificationCommand -) { - return request.post({ - url: `/api/admin/v1/tenants/${tenantId}/verification`, - data: { ...data, tenantId } - }) -} - -/** - * 创建租户订阅 - * @param tenantId 租户ID - * @param data 订阅参数 - */ -export function createTenantSubscription( - tenantId: string, - data: Api.Tenant.CreateTenantSubscriptionCommand -) { - return request.post({ - url: `/api/admin/v1/tenants/${tenantId}/subscriptions`, - data: { ...data, tenantId } - }) -} - -/** - * 初次绑定租户订阅(自助入驻) - * @param tenantId 租户ID - * @param data 初次绑定参数 - */ -export function bindInitialTenantSubscription( - tenantId: string, - data: Api.Tenant.BindInitialTenantSubscriptionCommand -) { - return request.post({ - url: `/api/public/v1/tenants/${tenantId}/subscriptions/initial`, - data: { ...data, tenantId } - }) -} - -/** - * 升降配租户套餐 - * @param tenantId 租户ID - * @param subscriptionId 订阅ID - * @param data 升降配参数 - */ -export function changeTenantSubscriptionPlan( - tenantId: string, - subscriptionId: string, - data: Api.Tenant.ChangeTenantSubscriptionPlanCommand -) { - return request.put({ - url: `/api/admin/v1/tenants/${tenantId}/subscriptions/${subscriptionId}/plan`, - data: { ...data, tenantId, tenantSubscriptionId: subscriptionId } - }) -} diff --git a/src/components/announcement/AudienceSelector.vue b/src/components/announcement/AudienceSelector.vue index 8bcdd4c..858ab6d 100644 --- a/src/components/announcement/AudienceSelector.vue +++ b/src/components/announcement/AudienceSelector.vue @@ -329,25 +329,25 @@ } const targetTypeOptions: Array<{ value: AnnouncementTargetType; labelKey: string }> = [ - { value: 'all', labelKey: 'announcement.audience.type.all' }, - { value: 'roles', labelKey: 'announcement.audience.type.roles' }, - { value: 'users', labelKey: 'announcement.audience.type.users' }, - { value: 'rules', labelKey: 'announcement.audience.type.rules' }, - { value: 'manual', labelKey: 'announcement.audience.type.manual' } + { value: 'All', labelKey: 'announcement.audience.type.all' }, + { value: 'Roles', labelKey: 'announcement.audience.type.roles' }, + { value: 'Users', labelKey: 'announcement.audience.type.users' }, + { value: 'Rules', labelKey: 'announcement.audience.type.rules' }, + { value: 'Manual', labelKey: 'announcement.audience.type.manual' } ] const targetTypeHelperMap: Record = { - all: 'announcement.audience.helper.all', - roles: 'announcement.audience.helper.roles', - users: 'announcement.audience.helper.users', - rules: 'announcement.audience.helper.rules', - manual: 'announcement.audience.helper.manual' + All: 'announcement.audience.helper.all', + Roles: 'announcement.audience.helper.roles', + Users: 'announcement.audience.helper.users', + Rules: 'announcement.audience.helper.rules', + Manual: 'announcement.audience.helper.manual' } // 2. 本地状态与加载状态 const currentTenantId = computed(() => String(userStore.info?.tenantId || '')) const localState = reactive({ - targetType: 'all' as AnnouncementTargetType, + targetType: 'All' as AnnouncementTargetType, rules: { departments: [] as string[], roles: [] as string[], @@ -371,10 +371,10 @@ const isSyncing = ref(false) // 3. 计算属性 - const isRoleMode = computed(() => localState.targetType === 'roles') - const isUsersMode = computed(() => localState.targetType === 'users') - const isRulesMode = computed(() => localState.targetType === 'rules') - const isManualMode = computed(() => localState.targetType === 'manual') + const isRoleMode = computed(() => localState.targetType === 'Roles') + const isUsersMode = computed(() => localState.targetType === 'Users') + const isRulesMode = computed(() => localState.targetType === 'Rules') + const isManualMode = computed(() => localState.targetType === 'Manual') const isRulesOrRoles = computed(() => isRulesMode.value || isRoleMode.value) const selectedUserCount = computed(() => localState.userIds.length) @@ -390,7 +390,7 @@ })) }) - const manualTransferTitles = computed(() => [ + const manualTransferTitles = computed<[string, string]>(() => [ t('announcement.audience.manual.transferLeft'), t('announcement.audience.manual.transferRight') ]) @@ -415,12 +415,14 @@ } } - const buildRulesPayload = (mode: 'rules' | 'roles'): TargetRules => { + const buildRulesPayload = ( + mode: Extract + ): TargetRules => { // 1. 获取清洗后的规则数据 const cleaned = normalizeRules(localState.rules) // 2. 角色模式仅返回角色规则 - if (mode === 'roles') { + if (mode === 'Roles') { return { roles: cleaned.roles } @@ -435,8 +437,8 @@ const targetType = localState.targetType // 2. 角色与规则模式 - if (targetType === 'roles' || targetType === 'rules') { - const rules = buildRulesPayload(targetType === 'roles' ? 'roles' : 'rules') + if (targetType === 'Roles' || targetType === 'Rules') { + const rules = buildRulesPayload(targetType) const hasRules = (rules.departments && rules.departments.length > 0) || (rules.roles && rules.roles.length > 0) || @@ -449,7 +451,7 @@ } // 3. 指定用户与手动选择 - if (targetType === 'users' || targetType === 'manual') { + if (targetType === 'Users' || targetType === 'Manual') { const userIds = normalizeArray(localState.userIds) return { @@ -494,9 +496,12 @@ // 1. 仅规则/角色模式触发 if (!isRulesOrRoles.value) return + const targetType = localState.targetType + if (targetType !== 'Rules' && targetType !== 'Roles') return + // 2. 发起预估请求 estimateLoading.value = true - const rules = buildRulesPayload(localState.targetType === 'roles' ? 'roles' : 'rules') + const rules = buildRulesPayload(targetType) const estimate = await announcementStore.estimateAudience(rules) // 3. 更新预估结果 @@ -645,25 +650,32 @@ } } - const handleUserSuggestions = useDebounceFn( - async (queryString: string, callback: (results: UserSuggestion[]) => void) => { - // 1. 拉取候选用户 - const options = await searchUsers(queryString) + const fetchUserSuggestionsDebounced = useDebounceFn(async (queryString: string) => { + // 1. 拉取候选用户 + const options = await searchUsers(queryString) - // 2. 转换为自动完成格式 - const suggestions = options.map((option) => ({ + // 2. 转换为自动完成格式 + return options.map( + (option): UserSuggestion => ({ value: option.label, label: option.label, id: option.id, option - })) + }) + ) + }, 300) - callback(suggestions) - }, - 300 - ) + const handleUserSuggestions = ( + queryString: string, + callback: (results: UserSuggestion[]) => void + ) => { + void fetchUserSuggestionsDebounced(queryString) + .then((suggestions) => callback(suggestions)) + .catch(() => callback([])) + } - const handleUserSelect = (suggestion: UserSuggestion) => { + const handleUserSelect = (item: Record) => { + const suggestion = item as UserSuggestion // 1. 写入候选列表 upsertUserOption(suggestion.option) @@ -689,7 +701,7 @@ isSyncing.value = true // 2. 同步目标类型 - localState.targetType = value?.targetType ?? 'all' + localState.targetType = value?.targetType ?? 'All' // 3. 同步规则与用户列表 const normalizedRules = normalizeRules(value?.targetRules) diff --git a/src/router/guards/beforeEach.ts b/src/router/guards/beforeEach.ts index 07cbc17..9f079aa 100644 --- a/src/router/guards/beforeEach.ts +++ b/src/router/guards/beforeEach.ts @@ -230,14 +230,7 @@ function handleLoginStatus( * 检查路由是否为无需登录的静态路由 */ function isPublicStaticRoute(path: string): boolean { - // 0. 入驻相关页面虽然是静态路由,但要求登录访问 - const loginRequiredStaticPaths = [ - '/onboarding/status', - '/onboarding/pricing', - '/onboarding/waiting', - '/onboarding/error' - ] - return isStaticRoute(path) && !loginRequiredStaticPaths.includes(path) + return isStaticRoute(path) } /** diff --git a/src/router/modules/dictionary.ts b/src/router/modules/dictionary.ts index 5209a23..43962a3 100644 --- a/src/router/modules/dictionary.ts +++ b/src/router/modules/dictionary.ts @@ -26,28 +26,6 @@ const dictionaryRoutes: AppRouteRecord = { permission: ['dictionary:group:read'] } }, - { - path: 'tenant', - name: 'TenantDictionary', - component: () => import('@views/tenant/dictionary/index.vue'), - meta: { - title: 'menus.dictionary.tenant', - icon: 'ri:bookmark-3-line', - roles: ['TenantAdmin'], - permission: ['dictionary:group:read'] - } - }, - { - path: 'override', - name: 'TenantDictionaryOverride', - component: () => import('@views/tenant/dictionary-override/index.vue'), - meta: { - title: 'menus.dictionary.override', - icon: 'ri:settings-3-line', - roles: ['TenantAdmin'], - permission: ['dictionary:override:read'] - } - }, { path: 'label-override', name: 'PlatformLabelOverride', diff --git a/src/router/modules/tenant.ts b/src/router/modules/tenant.ts index ddb1ffa..2b0a91b 100644 --- a/src/router/modules/tenant.ts +++ b/src/router/modules/tenant.ts @@ -41,46 +41,6 @@ const tenantRoutes: AppRouteRecord = { icon: 'ri:bar-chart-box-line', isHideMenu: false } - }, - { - path: 'announcements', - name: 'TenantAnnouncementList', - component: () => import('@views/tenant/announcements/index.vue'), - meta: { - title: 'menus.announcement.tenant.list', - icon: 'ri:notification-3-line', - permission: ['tenant-announcement:read'], - authList: [ - { title: '创建租户公告', authMark: 'tenant-announcement:create' }, - { title: '查看租户公告', authMark: 'tenant-announcement:read' }, - { title: '编辑租户公告', authMark: 'tenant-announcement:update' }, - { title: '删除租户公告', authMark: 'tenant-announcement:delete' }, - { title: '发布租户公告', authMark: 'tenant-announcement:publish' }, - { title: '撤销租户公告', authMark: 'tenant-announcement:revoke' } - ] - } - }, - { - path: 'announcements/create', - name: 'TenantAnnouncementCreate', - component: () => import('@views/tenant/announcements/create.vue'), - meta: { - title: 'menus.announcement.tenant.create', - icon: 'ri:add-circle-line', - permission: ['tenant-announcement:create'], - hideMenu: true - } - }, - { - path: 'announcements/:announcementId/edit', - name: 'TenantAnnouncementEdit', - component: () => import('@views/tenant/announcements/create.vue'), - meta: { - title: 'menus.announcement.tenant.edit', - icon: 'ri:edit-line', - permission: ['tenant-announcement:update'], - hideMenu: true - } } ] } diff --git a/src/router/routes/staticRoutes.ts b/src/router/routes/staticRoutes.ts index 7af56d7..42c1e2e 100644 --- a/src/router/routes/staticRoutes.ts +++ b/src/router/routes/staticRoutes.ts @@ -24,42 +24,6 @@ export const staticRoutes: AppRouteRecordRaw[] = [ component: () => import('@views/auth/login/index.vue'), meta: { title: 'menus.login.title', isHideTab: true } }, - { - path: '/auth/register', - name: 'Register', - component: () => import('@views/auth/register/index.vue'), - meta: { title: 'menus.register.title', isHideTab: true } - }, - { - path: '/onboarding/status', - name: 'TenantOnboardingStatus', - component: () => import('@views/onboarding/status/index.vue'), - meta: { title: 'menus.onboarding.status', isHideTab: true } - }, - { - path: '/onboarding/pricing', - name: 'TenantOnboardingPricing', - component: () => import('@views/onboarding/pricing/index.vue'), - meta: { title: 'menus.onboarding.pricing', isHideTab: true } - }, - { - path: '/onboarding/waiting', - name: 'TenantOnboardingWaiting', - component: () => import('@views/onboarding/waiting/index.vue'), - meta: { title: 'menus.onboarding.waiting', isHideTab: true } - }, - { - path: '/onboarding/error', - name: 'TenantOnboardingError', - component: () => import('@views/onboarding/error/index.vue'), - meta: { title: 'menus.onboarding.error', isHideTab: true } - }, - { - path: '/terms-of-service', - name: 'TermsOfService', - component: () => import('@views/onboarding/terms-of-service/index.vue'), - meta: { title: 'menus.termsOfService.title', isHideTab: true } - }, { path: '/auth/forget-password', name: 'ForgetPassword', diff --git a/src/store/modules/announcement.ts b/src/store/modules/announcement.ts index 7e4dc36..931f755 100644 --- a/src/store/modules/announcement.ts +++ b/src/store/modules/announcement.ts @@ -231,13 +231,13 @@ export const useAnnouncementStore = defineStore( } // 2. 规则/角色模式使用规则参数 - if ((data.targetType === 'rules' || data.targetType === 'roles') && data.targetRules) { + if ((data.targetType === 'Rules' || data.targetType === 'Roles') && data.targetRules) { return JSON.stringify(data.targetRules) } // 3. 手选用户模式使用用户ID参数 if ( - (data.targetType === 'users' || data.targetType === 'manual') && + (data.targetType === 'Users' || data.targetType === 'Manual') && data.targetUserIds?.length ) { return JSON.stringify({ userIds: data.targetUserIds }) @@ -272,6 +272,10 @@ export const useAnnouncementStore = defineStore( return { title: data.title, content: data.content, + announcementType: data.announcementType, + priority: data.priority, + effectiveFrom: data.effectiveFrom, + effectiveTo: data.effectiveTo ?? null, targetType: data.targetType, targetParameters: buildTargetParameters(data), rowVersion: data.rowVersion @@ -998,7 +1002,7 @@ export const useAnnouncementStore = defineStore( { // 使用 storeId 走全局 StorageKeyManager(避免硬编码 Key) persist: { - paths: ['unreadCount', 'statistics'] + pick: ['unreadCount', 'statistics'] } } ) diff --git a/src/store/modules/dictionaryCache.ts b/src/store/modules/dictionaryCache.ts index 5a09838..db33aa9 100644 --- a/src/store/modules/dictionaryCache.ts +++ b/src/store/modules/dictionaryCache.ts @@ -114,7 +114,7 @@ export const useDictionaryCacheStore = defineStore( }, { persist: { - paths: ['cache', 'expiryMap'] + pick: ['cache', 'expiryMap'] } } ) diff --git a/src/views/announcement-drafts/index.vue b/src/views/announcement-drafts/index.vue index fde6eb1..6900214 100644 --- a/src/views/announcement-drafts/index.vue +++ b/src/views/announcement-drafts/index.vue @@ -179,8 +179,8 @@ const actionLoadingIds = ref([]) const filters = ref({ - type: null as TenantAnnouncementType | null, - dateRange: [] as Date[] + type: undefined as TenantAnnouncementType | undefined, + dateRange: [] as [Date, Date] | [] }) const pagination = ref({ @@ -202,7 +202,6 @@ // 3. 选项配置 const announcementTypeOptions = computed(() => [ - { value: null, label: t('announcementDrafts.type.all') }, { value: TenantAnnouncementType.System, label: t('announcementDrafts.type.system') }, { value: TenantAnnouncementType.Billing, label: t('announcementDrafts.type.billing') }, { value: TenantAnnouncementType.Operation, label: t('announcementDrafts.type.operation') }, @@ -280,7 +279,7 @@ // 2. 过滤草稿列表 return mergedDrafts.value.filter((item) => { // 1. 类型筛选 - if (typeFilter !== null && item.announcementType !== typeFilter) { + if (typeFilter !== undefined && item.announcementType !== typeFilter) { return false } @@ -356,8 +355,9 @@ const resolveServerLastSaved = (draft: TenantAnnouncementDto): IsoDateTimeString | null => { // 1. 兼容后端可能返回的更新时间字段 const candidateFields = ['updatedAt', 'lastSaved', 'modifiedAt', 'createdAt'] as const + const record = draft as unknown as Record for (const field of candidateFields) { - const value = (draft as Record)[field] + const value = record[field] if (typeof value === 'string' && value) { return value } @@ -676,7 +676,7 @@ const handleReset = async () => { // 1. 重置筛选条件 - filters.value.type = null + filters.value.type = undefined filters.value.dateRange = [] // 2. 重置分页 diff --git a/src/views/auth/login/index.vue b/src/views/auth/login/index.vue index 0ef161c..c13aabe 100644 --- a/src/views/auth/login/index.vue +++ b/src/views/auth/login/index.vue @@ -90,12 +90,7 @@ -
- {{ $t('login.noAccount') }} - {{ - $t('login.register') - }} -
+ @@ -109,9 +104,7 @@ import { useI18n } from 'vue-i18n' import { HttpError } from '@/utils/http/error' import { fetchLoginSimple } from '@/api/auth' - import { fetchTenantProgress } from '@/api/tenant-onboarding' import { ElNotification, type FormInstance, type FormRules } from 'element-plus' - import { StorageConfig } from '@/utils/storage' import { clearRememberLogin, loadRememberLogin, @@ -135,21 +128,6 @@ const route = useRoute() const isPassing = ref(true) - // 本地枚举,避免运行时引用未定义的 Api 命名空间 - const TenantVerificationStatus = { - Draft: 0, - Pending: 1, - Approved: 2, - Rejected: 3 - } as const - const TenantStatus = { - PendingReview: 0, - Active: 1, - Suspended: 2, - Expired: 3, - Closed: 4 - } as const - const systemName = AppConfig.systemInfo.name const formRef = ref() @@ -230,18 +208,15 @@ userStore.setToken(accessToken, refreshToken) if (user) { userStore.setUserInfo(user) - if (user.tenantId) { - localStorage.setItem(StorageConfig.TENANT_ID_KEY, String(user.tenantId)) - } } userStore.setLoginStatus(true) // 8. 登录成功处理 showLoginSuccessNotice() - // 9. 跳转前检查租户入驻状态 - const redirect = route.query.redirect as string - await handlePostLoginNavigation(redirect) + // 9. 登录后跳转(平台管理端不处理租户入驻流程) + const redirect = route.query.redirect as string | undefined + router.push(redirect || '/') } catch (error) { // 处理 HttpError if (error instanceof HttpError) { @@ -264,72 +239,6 @@ } } - const handlePostLoginNavigation = async (redirect?: string) => { - const tenantId = - (route.query.tenantId as string) || - userStore.getUserInfo?.tenantId || - localStorage.getItem(StorageConfig.TENANT_ID_KEY) - - // 1. 拉取入驻进度 - if (!tenantId) { - router.push(redirect || '/') - return - } - - try { - const progress = await fetchTenantProgress(String(tenantId)) - - // 2. 判定登录后跳转目标 - const verificationStatus = progress.verificationStatus - const tenantStatus = progress.status - - // 2.1 草稿:引导选择套餐 - if (verificationStatus === TenantVerificationStatus.Draft) { - router.push({ - name: 'TenantOnboardingPricing', - query: { tenantId: String(tenantId) } - }) - return - } - - // 2.2 待审核:进入等待页 - if (verificationStatus === TenantVerificationStatus.Pending) { - router.push({ - name: 'TenantOnboardingWaiting', - query: { tenantId: String(tenantId) } - }) - return - } - - // 2.3 状态异常:实名驳回或租户不可用 - const isTenantErrorStatus = - tenantStatus === TenantStatus.Suspended || - tenantStatus === TenantStatus.Expired || - tenantStatus === TenantStatus.Closed - if (verificationStatus === TenantVerificationStatus.Rejected || isTenantErrorStatus) { - router.push({ - name: 'TenantOnboardingError', - query: { tenantId: String(tenantId) } - }) - return - } - - // 2.4 其他非通过场景兜底回进度页 - if (tenantStatus !== TenantStatus.Active) { - router.push({ - name: 'TenantOnboardingStatus', - query: { tenantId: String(tenantId) } - }) - return - } - } catch (error) { - console.warn('[Login] 入驻状态检查失败,按默认流程跳转:', error) - } - - // 3. 默认跳转控制台或 redirect - router.push(redirect || '/') - } - // 登录成功提示 const showLoginSuccessNotice = () => { setTimeout(() => { diff --git a/src/views/auth/register/index.vue b/src/views/auth/register/index.vue deleted file mode 100644 index 1e8683c..0000000 --- a/src/views/auth/register/index.vue +++ /dev/null @@ -1,668 +0,0 @@ - - - diff --git a/src/views/merchant/detail/modules/EditDialog.vue b/src/views/merchant/detail/modules/EditDialog.vue index d434e2d..9dc1fe5 100644 --- a/src/views/merchant/detail/modules/EditDialog.vue +++ b/src/views/merchant/detail/modules/EditDialog.vue @@ -111,20 +111,25 @@ } const handleSubmit = async () => { - if (!formRef.value) return - if (!currentMerchantId.value) return - if (!currentRowVersion.value) { + const form = formRef.value + if (!form) return + + const merchantId = currentMerchantId.value + if (!merchantId) return + + const rowVersion = currentRowVersion.value + if (!rowVersion) { ElMessage.error(t('merchant.message.rowVersionMissing')) return } - await formRef.value.validate(async (valid) => { + await form.validate(async (valid) => { if (!valid) return submitting.value = true try { const result = await fetchUpdateMerchant( - currentMerchantId.value, + merchantId, { name: formModel.name, licenseNumber: formModel.licenseNumber, @@ -132,7 +137,7 @@ registeredAddress: formModel.registeredAddress, contactPhone: formModel.contactPhone, contactEmail: formModel.contactEmail, - rowVersion: currentRowVersion.value + rowVersion }, { showErrorMessage: false } ) diff --git a/src/views/merchant/list/index.vue b/src/views/merchant/list/index.vue index 5e2dac6..ba6b10e 100644 --- a/src/views/merchant/list/index.vue +++ b/src/views/merchant/list/index.vue @@ -136,19 +136,19 @@ }) const handleSearch = (params: MerchantListSearchForm) => { - searchParams.Keyword = params.keyword || undefined - searchParams.Status = params.status - searchParams.OperatingMode = params.operatingMode - searchParams.TenantId = params.tenantId ? params.tenantId.trim() : undefined + searchParams.keyword = params.keyword || undefined + searchParams.status = params.status + searchParams.operatingMode = params.operatingMode + searchParams.tenantId = params.tenantId ? params.tenantId.trim() : undefined refreshData() } const handleReset = () => { formFilters.value = { keyword: '', status: undefined, operatingMode: undefined, tenantId: '' } - searchParams.Keyword = undefined - searchParams.Status = undefined - searchParams.OperatingMode = undefined - searchParams.TenantId = undefined + searchParams.keyword = undefined + searchParams.status = undefined + searchParams.operatingMode = undefined + searchParams.tenantId = undefined refreshData() } diff --git a/src/views/onboarding/error/index.vue b/src/views/onboarding/error/index.vue deleted file mode 100644 index 50e1028..0000000 --- a/src/views/onboarding/error/index.vue +++ /dev/null @@ -1,459 +0,0 @@ - - - - diff --git a/src/views/onboarding/pricing/index.vue b/src/views/onboarding/pricing/index.vue deleted file mode 100644 index 29837d9..0000000 --- a/src/views/onboarding/pricing/index.vue +++ /dev/null @@ -1,513 +0,0 @@ - - - - - diff --git a/src/views/onboarding/status/index.vue b/src/views/onboarding/status/index.vue deleted file mode 100644 index db995af..0000000 --- a/src/views/onboarding/status/index.vue +++ /dev/null @@ -1,689 +0,0 @@ - - - - - diff --git a/src/views/onboarding/terms-of-service/index.vue b/src/views/onboarding/terms-of-service/index.vue deleted file mode 100644 index b4df1df..0000000 --- a/src/views/onboarding/terms-of-service/index.vue +++ /dev/null @@ -1,227 +0,0 @@ - - - - - diff --git a/src/views/onboarding/waiting/index.vue b/src/views/onboarding/waiting/index.vue deleted file mode 100644 index ac437cd..0000000 --- a/src/views/onboarding/waiting/index.vue +++ /dev/null @@ -1,376 +0,0 @@ - - - - - diff --git a/src/views/platform/announcements/create.vue b/src/views/platform/announcements/create.vue index e5e0f62..69f6ac6 100644 --- a/src/views/platform/announcements/create.vue +++ b/src/views/platform/announcements/create.vue @@ -154,7 +154,7 @@ priority: 1, effectiveFrom: new Date().toISOString(), effectiveTo: null, - targetType: 'all', + targetType: 'All', targetRules: undefined, targetUserIds: [], rowVersion: undefined @@ -302,7 +302,7 @@ formModel.priority = draft.priority ?? 1 formModel.effectiveFrom = draft.effectiveFrom ?? new Date().toISOString() formModel.effectiveTo = draft.effectiveTo ?? null - formModel.targetType = draft.targetType ?? 'all' + formModel.targetType = draft.targetType ?? 'All' formModel.targetRules = draft.targetRules formModel.targetUserIds = draft.targetUserIds ?? [] } @@ -327,12 +327,12 @@ return t('announcement.validation.targetTypeRequired') } - if ((targetType === 'rules' || targetType === 'roles') && !formModel.targetRules) { + if ((targetType === 'Rules' || targetType === 'Roles') && !formModel.targetRules) { return t('announcement.validation.targetRulesRequired') } if ( - (targetType === 'users' || targetType === 'manual') && + (targetType === 'Users' || targetType === 'Manual') && (!formModel.targetUserIds || formModel.targetUserIds.length === 0) ) { return t('announcement.validation.targetUsersRequired') diff --git a/src/views/platform/announcements/edit.vue b/src/views/platform/announcements/edit.vue index 53f56d4..36dade2 100644 --- a/src/views/platform/announcements/edit.vue +++ b/src/views/platform/announcements/edit.vue @@ -183,7 +183,7 @@ priority: 1, effectiveFrom: new Date().toISOString(), effectiveTo: null, - targetType: 'all', + targetType: 'All', targetRules: undefined, targetUserIds: [], rowVersion: undefined @@ -288,12 +288,12 @@ return t('announcement.validation.targetTypeRequired') } - if ((targetType === 'rules' || targetType === 'roles') && !formModel.targetRules) { + if ((targetType === 'Rules' || targetType === 'Roles') && !formModel.targetRules) { return t('announcement.validation.targetRulesRequired') } if ( - (targetType === 'users' || targetType === 'manual') && + (targetType === 'Users' || targetType === 'Manual') && (!formModel.targetUserIds || formModel.targetUserIds.length === 0) ) { return t('announcement.validation.targetUsersRequired') @@ -477,11 +477,11 @@ try { const parsed = JSON.parse(raw) as unknown - if ((targetType === 'rules' || targetType === 'roles') && isTargetRules(parsed)) { + if ((targetType === 'Rules' || targetType === 'Roles') && isTargetRules(parsed)) { return { targetRules: parsed, targetUserIds: [] as string[] } } - if ((targetType === 'users' || targetType === 'manual') && isUserIdsPayload(parsed)) { + if ((targetType === 'Users' || targetType === 'Manual') && isUserIdsPayload(parsed)) { return { targetRules: undefined, targetUserIds: parsed.userIds } } } catch { diff --git a/src/views/platform/qualification-alerts/index.vue b/src/views/platform/qualification-alerts/index.vue index 503514d..34c3536 100644 --- a/src/views/platform/qualification-alerts/index.vue +++ b/src/views/platform/qualification-alerts/index.vue @@ -30,7 +30,7 @@ @@ -193,9 +193,9 @@ // 4. 查询操作 const handleSearch = () => { - searchParams.TenantId = formFilters.value.tenantId.trim() || undefined - searchParams.DaysThreshold = formFilters.value.daysThreshold || undefined - searchParams.Expired = formFilters.value.expired + searchParams.tenantId = formFilters.value.tenantId.trim() || undefined + searchParams.daysThreshold = formFilters.value.daysThreshold || undefined + searchParams.expired = formFilters.value.expired refreshData() } const handleReset = () => { @@ -204,9 +204,9 @@ daysThreshold: undefined, expired: undefined } - searchParams.TenantId = undefined - searchParams.DaysThreshold = undefined - searchParams.Expired = undefined + searchParams.tenantId = undefined + searchParams.daysThreshold = undefined + searchParams.expired = undefined refreshData() } diff --git a/src/views/platform/store-audits/index.vue b/src/views/platform/store-audits/index.vue index 4257826..b19091a 100644 --- a/src/views/platform/store-audits/index.vue +++ b/src/views/platform/store-audits/index.vue @@ -177,8 +177,8 @@ apiParams: { Page: 1, PageSize: 20, - SortBy: 'SubmittedAt', - SortDesc: true + sortBy: 'SubmittedAt', + sortDesc: true }, paginationKey: { current: 'Page', @@ -217,11 +217,11 @@ // 4. 查询与操作 const handleSearch = () => { const [submittedFrom, submittedTo] = formFilters.value.dateRange || [] - searchParams.Keyword = formFilters.value.keyword.trim() || undefined - searchParams.TenantId = formFilters.value.tenantId.trim() || undefined - searchParams.SubmittedFrom = submittedFrom || undefined - searchParams.SubmittedTo = submittedTo || undefined - searchParams.OverdueOnly = formFilters.value.overdueOnly + searchParams.keyword = formFilters.value.keyword.trim() || undefined + searchParams.tenantId = formFilters.value.tenantId.trim() || undefined + searchParams.submittedFrom = submittedFrom || undefined + searchParams.submittedTo = submittedTo || undefined + searchParams.overdueOnly = formFilters.value.overdueOnly refreshData() void loadStatistics() } @@ -232,11 +232,11 @@ dateRange: [], overdueOnly: false } - searchParams.Keyword = undefined - searchParams.TenantId = undefined - searchParams.SubmittedFrom = undefined - searchParams.SubmittedTo = undefined - searchParams.OverdueOnly = false + searchParams.keyword = undefined + searchParams.tenantId = undefined + searchParams.submittedFrom = undefined + searchParams.submittedTo = undefined + searchParams.overdueOnly = false refreshData() void loadStatistics() } @@ -256,8 +256,8 @@ const loadStatistics = async () => { const [dateFrom, dateTo] = formFilters.value.dateRange || [] statistics.value = await fetchStoreAuditStatistics({ - DateFrom: dateFrom || undefined, - DateTo: dateTo || undefined + dateFrom: dateFrom || undefined, + dateTo: dateTo || undefined }) } diff --git a/src/views/store/store-list/components/BusinessStatusDialog.vue b/src/views/store/store-list/components/BusinessStatusDialog.vue index 4d763b8..2f64e38 100644 --- a/src/views/store/store-list/components/BusinessStatusDialog.vue +++ b/src/views/store/store-list/components/BusinessStatusDialog.vue @@ -192,12 +192,14 @@ }) const handleSubmit = async () => { - if (!store.value || !formRef.value) { - return - } + const form = formRef.value + const currentStore = store.value + if (!currentStore || !form) return + + const storeId = String(currentStore.id) // 1. 校验表单 - await formRef.value.validate(async (valid) => { + await form.validate(async (valid) => { if (!valid) { return } @@ -205,7 +207,7 @@ // 2. 提交状态变更 saving.value = true try { - await fetchToggleBusinessStatus(String(store.value.id), buildPayload()) + await fetchToggleBusinessStatus(storeId, buildPayload()) ElMessage.success(t('store.message.statusUpdated')) emit('saved') dialogVisible.value = false diff --git a/src/views/store/store-list/index.vue b/src/views/store/store-list/index.vue index bfaf744..dcab60d 100644 --- a/src/views/store/store-list/index.vue +++ b/src/views/store/store-list/index.vue @@ -201,11 +201,11 @@ // 5. 搜索与操作 const handleSearch = () => { - searchParams.Keyword = formFilters.value.keyword.trim() || undefined - searchParams.MerchantId = formFilters.value.merchantId.trim() || undefined - searchParams.AuditStatus = formFilters.value.auditStatus - searchParams.BusinessStatus = formFilters.value.businessStatus - searchParams.OwnershipType = formFilters.value.ownershipType + searchParams.keyword = formFilters.value.keyword.trim() || undefined + searchParams.merchantId = formFilters.value.merchantId.trim() || undefined + searchParams.auditStatus = formFilters.value.auditStatus + searchParams.businessStatus = formFilters.value.businessStatus + searchParams.ownershipType = formFilters.value.ownershipType refreshData() } const handleReset = () => { @@ -216,11 +216,11 @@ businessStatus: undefined, ownershipType: undefined } - searchParams.Keyword = undefined - searchParams.MerchantId = undefined - searchParams.AuditStatus = undefined - searchParams.BusinessStatus = undefined - searchParams.OwnershipType = undefined + searchParams.keyword = undefined + searchParams.merchantId = undefined + searchParams.auditStatus = undefined + searchParams.businessStatus = undefined + searchParams.ownershipType = undefined refreshData() } const handleCreate = () => { diff --git a/src/views/system/user/index.vue b/src/views/system/user/index.vue index 6d2d3b0..b8786d4 100644 --- a/src/views/system/user/index.vue +++ b/src/views/system/user/index.vue @@ -271,6 +271,7 @@ import { ElMessage, ElMessageBox } from 'element-plus' import { useTable } from '@/hooks/core/useTable' import { useUserStore } from '@/store/modules/user' + import type { ColumnOption } from '@/types/component' import { formatDateTime } from '@/utils/billing' import { isHttpError } from '@/utils/http/error' import { @@ -392,7 +393,7 @@ // 3. 正常状态映射 const statusMap: Record< IdentityUserStatus, - { label: string; type: 'success' | 'danger' | 'info' } + { label: string; type: 'success' | 'danger' | 'info' | 'warning' } > = { 1: { label: t('user.status.active'), type: 'success' }, 2: { label: t('user.status.disabled'), type: 'danger' }, @@ -416,9 +417,9 @@ permissionLabelMap.value.get(permission) || permission // 4. 表格与查询逻辑 - const buildColumns = () => { + const buildColumns = (): ColumnOption[] => { // 1. 构建基础列 - const columns = [ + const columns: ColumnOption[] = [ { type: 'selection', width: 50 }, { type: 'globalIndex', width: 60, label: t('table.column.index') }, { diff --git a/src/views/system/user/modules/user-dialog.vue b/src/views/system/user/modules/user-dialog.vue index 8c7ba32..7fc1e29 100644 --- a/src/views/system/user/modules/user-dialog.vue +++ b/src/views/system/user/modules/user-dialog.vue @@ -390,7 +390,7 @@ const initFormData = () => { // 1. 解析详情与默认租户 const detail = props.userData - const defaultTenantId = props.defaultTenantId || props.tenantOptions[0]?.value || '' + const defaultTenantId = String(props.defaultTenantId || props.tenantOptions[0]?.value || '') // 2. 编辑模式填充 if (isEdit.value && detail) { @@ -411,7 +411,7 @@ } // 3. 新增模式初始化 - formData.tenantId = detail?.tenantId || defaultTenantId + formData.tenantId = String(detail?.tenantId || defaultTenantId || '') formData.account = '' formData.displayName = '' formData.password = '' diff --git a/src/views/tenant/announcements/components/AnnouncementDetailDrawer.vue b/src/views/tenant/announcements/components/AnnouncementDetailDrawer.vue deleted file mode 100644 index ea74cbc..0000000 --- a/src/views/tenant/announcements/components/AnnouncementDetailDrawer.vue +++ /dev/null @@ -1,404 +0,0 @@ - - - diff --git a/src/views/tenant/announcements/components/AnnouncementFormDialog.vue b/src/views/tenant/announcements/components/AnnouncementFormDialog.vue deleted file mode 100644 index 0c71481..0000000 --- a/src/views/tenant/announcements/components/AnnouncementFormDialog.vue +++ /dev/null @@ -1,463 +0,0 @@ - - - diff --git a/src/views/tenant/announcements/create.vue b/src/views/tenant/announcements/create.vue deleted file mode 100644 index 937859b..0000000 --- a/src/views/tenant/announcements/create.vue +++ /dev/null @@ -1,746 +0,0 @@ - - - diff --git a/src/views/tenant/announcements/edit.vue b/src/views/tenant/announcements/edit.vue deleted file mode 100644 index 9c2e29c..0000000 --- a/src/views/tenant/announcements/edit.vue +++ /dev/null @@ -1,621 +0,0 @@ - - - diff --git a/src/views/tenant/announcements/index.vue b/src/views/tenant/announcements/index.vue deleted file mode 100644 index 6b12240..0000000 --- a/src/views/tenant/announcements/index.vue +++ /dev/null @@ -1,698 +0,0 @@ - - - - - diff --git a/src/views/tenant/dictionary-override/components/CustomItemsPanel.vue b/src/views/tenant/dictionary-override/components/CustomItemsPanel.vue deleted file mode 100644 index a280abf..0000000 --- a/src/views/tenant/dictionary-override/components/CustomItemsPanel.vue +++ /dev/null @@ -1,201 +0,0 @@ - - - - - diff --git a/src/views/tenant/dictionary-override/components/DualPaneView.vue b/src/views/tenant/dictionary-override/components/DualPaneView.vue deleted file mode 100644 index b675863..0000000 --- a/src/views/tenant/dictionary-override/components/DualPaneView.vue +++ /dev/null @@ -1,63 +0,0 @@ - - - - - diff --git a/src/views/tenant/dictionary-override/components/LabelOverrideFormDialog.vue b/src/views/tenant/dictionary-override/components/LabelOverrideFormDialog.vue deleted file mode 100644 index 3b1aae2..0000000 --- a/src/views/tenant/dictionary-override/components/LabelOverrideFormDialog.vue +++ /dev/null @@ -1,274 +0,0 @@ - - - - - diff --git a/src/views/tenant/dictionary-override/components/LabelOverridePanel.vue b/src/views/tenant/dictionary-override/components/LabelOverridePanel.vue deleted file mode 100644 index 2a597a8..0000000 --- a/src/views/tenant/dictionary-override/components/LabelOverridePanel.vue +++ /dev/null @@ -1,269 +0,0 @@ - - - - - diff --git a/src/views/tenant/dictionary-override/components/OverrideToggle.vue b/src/views/tenant/dictionary-override/components/OverrideToggle.vue deleted file mode 100644 index a6136c9..0000000 --- a/src/views/tenant/dictionary-override/components/OverrideToggle.vue +++ /dev/null @@ -1,68 +0,0 @@ - - - - - diff --git a/src/views/tenant/dictionary-override/components/SortableDragDrop.vue b/src/views/tenant/dictionary-override/components/SortableDragDrop.vue deleted file mode 100644 index 8336493..0000000 --- a/src/views/tenant/dictionary-override/components/SortableDragDrop.vue +++ /dev/null @@ -1,175 +0,0 @@ - - - - - diff --git a/src/views/tenant/dictionary-override/components/SystemItemsPanel.vue b/src/views/tenant/dictionary-override/components/SystemItemsPanel.vue deleted file mode 100644 index 8776873..0000000 --- a/src/views/tenant/dictionary-override/components/SystemItemsPanel.vue +++ /dev/null @@ -1,107 +0,0 @@ - - - - - diff --git a/src/views/tenant/dictionary-override/index.vue b/src/views/tenant/dictionary-override/index.vue deleted file mode 100644 index 5a8d81a..0000000 --- a/src/views/tenant/dictionary-override/index.vue +++ /dev/null @@ -1,261 +0,0 @@ - - - - - diff --git a/src/views/tenant/dictionary/index.vue b/src/views/tenant/dictionary/index.vue deleted file mode 100644 index 30da699..0000000 --- a/src/views/tenant/dictionary/index.vue +++ /dev/null @@ -1,44 +0,0 @@ - - - - - diff --git a/src/views/tenant/review/components/ReviewDialog.vue b/src/views/tenant/review/components/ReviewDialog.vue index 3c63e80..458a8b5 100644 --- a/src/views/tenant/review/components/ReviewDialog.vue +++ b/src/views/tenant/review/components/ReviewDialog.vue @@ -505,7 +505,7 @@ rejectReasonKey: '' as RejectReasonKey | '', customRejectReason: '', renewMonths: 1 as number | null, - operatingMode: OperatingMode.SameEntity as OperatingMode | null + operatingMode: OperatingMode.SameEntity as OperatingMode | undefined }) const rules = computed(() => ({ @@ -613,7 +613,7 @@ form.operatingMode = form.operatingMode ?? OperatingMode.SameEntity } else { form.renewMonths = null - form.operatingMode = null + form.operatingMode = undefined } // 2. 触发表单校验刷新