| rencaika/pages/card/card.uvue | ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史 | |
| rencaika/pages/talent-code/talent-code.uvue | ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史 | |
| rencaika_merchant/pages/merchant-onboarding/merchant-onboarding.uvue | ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史 | |
| rencaika_merchant/pages/merchant/merchant.uvue | ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史 | |
| rencaika_merchant/pages/scan/scan.uvue | ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史 | |
| rencaika_merchant/pages/withdrawal-detail/withdrawal-detail.uvue | ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史 | |
| talent-card-admin/src/layouts/AdminLayout.vue | ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史 | |
| talent-card-admin/src/types/admin.ts | ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史 | |
| talent-card-admin/src/views/MerchantCreateView.vue | ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史 | |
| talent-card-admin/src/views/RoleFormView.vue | ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史 | |
| talent-card-admin/src/views/StaffManagementView.vue | ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史 |
rencaika/pages/card/card.uvue
@@ -48,14 +48,14 @@ <text class="refresh-tip">{{canShowCode ? refreshTip : '请联系服务专员了解卡片状态'}}</text> </view> <view v-if="advisorName != ''" class="service-panel"> <view v-if="canShowCode" class="service-panel"> <view class="service-title-row"><view class="title-line"></view><text>{{cardLevel}}专属服务专员</text><view class="title-line"></view></view> <text class="service-advisor">{{advisorDepartment}} {{advisorName}}</text> <text class="service-advisor">{{advisorName != '' ? advisorDepartment + ' ' + advisorName : '暂未配置服务专员'}}</text> <view class="service-actions"> <view v-if="advisorConsultUrl != ''" class="service-action" hover-class="service-action-active" @tap="onlineConsult"> <view class="service-action" hover-class="service-action-active" @tap="onlineConsult"> <image src="/static/card-assets/consult.png"></image><text>在线咨询</text> </view> <view v-if="advisorMobile != ''" class="service-action" hover-class="service-action-active" @tap="callAdvisor"> <view class="service-action" hover-class="service-action-active" @tap="callAdvisor"> <image src="/static/card-assets/phone.png"></image><text>拨打电话</text> </view> </view> @@ -75,8 +75,11 @@ <view v-if="showApplyNotice" class="apply-mask" @tap="closeApplyNotice"> <view class="apply-dialog" @tap.stop="preventClose"> <text class="dialog-title">温馨提示</text> <text class="dialog-copy">请前往东区政务服务中心(东区大渡口街86号)区人才综合服务专窗线下进行人才认定。</text> <text class="dialog-phone">0812-3509008,东区人才综合服务专窗</text> <text class="dialog-copy"> 请前往东区政务服务中心(东区大渡口街86号)线下进行人才认定。</text> <view class="dialog-contact"> <text class="dialog-phone">联系电话:0812-3509008</text> <text class="dialog-office">东区人才综合服务专窗</text> </view> <view class="dialog-confirm" hover-class="dialog-confirm-active" @tap="closeApplyNotice"><text>确定</text></view> </view> </view> @@ -209,7 +212,7 @@ if (!advisorConsultUrl.value.match(/^https:\/\//)) { uni.showToast({ title: '暂未配置在线咨询', icon: 'none' }); return } uni.navigateTo({ url: '/pages/external-webview/external-webview?source=advisor&talentId=' + encodeURIComponent(talentId.value) }) } const callAdvisor = () => { if (advisorMobile.value != '') uni.makePhoneCall({ phoneNumber: advisorMobile.value }) } const callAdvisor = () => { if (advisorMobile.value == '') { uni.showToast({ title: '暂未配置服务专员电话', icon: 'none' }); return }; uni.makePhoneCall({ phoneNumber: advisorMobile.value }) } const goHome = () => uni.reLaunch({ url: '/pages/index/index' }) const goBenefits = () => uni.reLaunch({ url: '/pages/benefits/benefits' }) const goPolicy = () => uni.reLaunch({ url: '/pages/policy/policy' }) @@ -293,7 +296,9 @@ .apply-dialog { width: 100%; box-sizing: border-box; padding: 59rpx 47rpx 39rpx; border-radius: 32rpx; background-color: #FFFFFF; } .dialog-title { display: block; color: #386BB0; font-size: 43rpx; line-height: 60rpx; font-weight: 700; text-align: center; } .dialog-copy { display: block; margin-top: 44rpx; color: #737F91; font-size: 27rpx; line-height: 42rpx; font-weight: 600; } .dialog-phone { display: block; margin-top: 16rpx; color: #FF8957; font-size: 27rpx; line-height: 39rpx; font-weight: 700; } .dialog-contact { display: flex; margin-top: 16rpx; flex-direction: column; align-items: flex-end; } .dialog-phone, .dialog-office { display: block; color: #FF8957; font-size: 27rpx; line-height: 39rpx; font-weight: 700; text-align: right; } .dialog-office { margin-top: 4rpx; } .dialog-confirm { display: flex; width: 200rpx; height: 60rpx; margin: 39rpx auto 0; border-radius: 31rpx; background-image: linear-gradient(90deg, #FF4A32 0%, #FF8A1B 100%); justify-content: center; align-items: center; } .dialog-confirm text { color: #FFFFFF; font-size: 27rpx; font-weight: 700; } .dialog-confirm-active { opacity: .78; } rencaika/pages/talent-code/talent-code.uvue
@@ -132,7 +132,6 @@ stopTimers() codeLoading.value = true codeLoadFailed.value = false codeImageUrl.value = '' codeMessage.value = '正在生成动态人才码' issueTalentDynamicCodeForScene(talentId.value, scene.value, merchantId.value, (data: any) => { codeLoading.value = false @@ -141,8 +140,13 @@ codeImageUrl.value = getApiBaseUrl().replace(/\/$/, '') + (data.imagePath as string) expiresAt.value = Number(data.expiresAt) setCountdown() const seconds = data.refreshAfterSeconds != null ? Number(data.refreshAfterSeconds) : 60 refreshTimer = setTimeout(() => requestDynamicCode(), Math.max(1, seconds - 2) * 1000) // Refresh only after the displayed code expires so the countdown never jumps back early. const refreshDelay = Math.max(1, expiresAt.value - Date.now()) refreshTimer = setTimeout(() => { remainingSeconds.value = 0 refreshTip.value = '正在刷新动态人才码' requestDynamicCode() }, refreshDelay) }, (error) => { if (pageVisible) handleCodeFailure(error.message); else codeLoading.value = false }) } const handleCodeFailure = (message: string) => { stopTimers(); codeLoading.value = false; codeImageUrl.value = ''; codeLoadFailed.value = true; codeMessage.value = message == '' ? '动态人才码加载失败' : message; refreshTip.value = '动态人才码已失效,请重新获取' } rencaika_merchant/pages/merchant-onboarding/merchant-onboarding.uvue
@@ -18,7 +18,7 @@ <view class="field-block"> <text class="field-label">统一社会信用代码</text> <view class="input-shell" :class="invalidField == 'creditCode' ? 'field-invalid' : ''"><input class="text-input" v-model="creditCode" maxlength="18" placeholder="请输入18位统一社会信用代码" placeholder-class="input-placeholder" @input="normalizeCreditCode" /></view> <view class="input-shell" :class="invalidField == 'creditCode' ? 'field-invalid' : ''"><input class="text-input" :value="creditCode" maxlength="18" placeholder="请输入18位统一社会信用代码" placeholder-class="input-placeholder" @input="normalizeCreditCode" /></view> <text v-if="invalidField == 'creditCode'" class="field-error">{{errorMessage}}</text> </view> @@ -160,8 +160,9 @@ } } const normalizeCreditCode = () => { creditCode.value = creditCode.value.toUpperCase().replace(/[^0-9A-Z]/g, '') const normalizeCreditCode = (event: any) => { const input = event != null && event.detail != null && event.detail.value != null ? '' + event.detail.value : '' creditCode.value = input.toUpperCase().replace(/[^0-9A-Z]/g, '') clearFieldError('creditCode') } rencaika_merchant/pages/merchant/merchant.uvue
@@ -19,8 +19,6 @@ </view> <view class="setting-card"> <view class="setting-row" @tap="handleMenuAction('结算管理')"><view class="setting-leading"><image class="setting-icon" src="/static/icons/lucide/hand-coins.svg" mode="aspectFit"></image><text class="setting-label">结算管理</text></view><image class="setting-chevron" src="/static/icons/lucide/chevron-right.svg" mode="aspectFit"></image></view> <view class="setting-row" @tap="handleMenuAction('商户提现')"><view class="setting-leading"><image class="setting-icon" src="/static/icons/lucide/wallet-cards-gray.svg" mode="aspectFit"></image><text class="setting-label">商户提现</text></view><image class="setting-chevron" src="/static/icons/lucide/chevron-right.svg" mode="aspectFit"></image></view> <view class="setting-row"> <view class="setting-leading"><image class="setting-icon" src="/static/icons/lucide/store.svg" mode="aspectFit"></image><text class="setting-label">营业状态</text></view> <view class="business-state" :class="businessUpdating ? 'business-state-disabled' : ''" @tap="toggleBusiness"><text class="business-state-text">{{isBusinessOpen ? '营业中' : '休息中'}}</text><view class="state-switch" :class="isBusinessOpen ? 'open' : ''"><view class="state-thumb"></view></view></view> @@ -93,10 +91,6 @@ } if (name === '商户提现') { uni.navigateTo({ url: '/pages/withdrawal/withdrawal' }) return } if (name === '结算管理') { uni.navigateTo({ url: '/pages/settlement-management/settlement-management' }) return } if (name === '营业时间') { rencaika_merchant/pages/scan/scan.uvue
@@ -101,7 +101,10 @@ canRetryVerification.value = false return } if (result.credentialType == 'TALENT_CODE') { // An order QR must always enter the confirmation page. Keep the order // number as a fallback discriminator for older/incorrect type payloads. const isTalentCode = result.credentialType == 'TALENT_CODE' && result.orderNo.length == 0 if (isTalentCode) { openedManualConsumption = true uni.navigateTo({ url: '/pages/consume-input/consume-input?verificationId=' + encodeURIComponent(result.verificationId) }) return rencaika_merchant/pages/withdrawal-detail/withdrawal-detail.uvue
@@ -1,15 +1,14 @@ <template> <view class="page"> <view class="navigation-bar"><view class="back-button" @tap="goBack"><image class="back-icon" src="/static/icons/lucide/back-left.svg" mode="aspectFit"></image></view><text class="page-title">商户提现</text></view> <view class="navigation-bar"><view class="back-button" @tap="goBack"><image class="back-icon" src="/static/icons/lucide/back-left-white.svg" mode="aspectFit"></image></view><text class="page-title">商户提现</text></view> <scroll-view class="form-scroll" scroll-y="true" :show-scrollbar="false" :enhanced="false"> <view class="available-row"><text class="available-label">当前可提</text><text class="available-value">¥{{availableText}}</text></view> <view class="form-card"> <view class="available-row"><text class="available-label">当前可提</text><text class="available-value">¥{{availableText}}</text></view> <view class="field-block"> <view class="field-row amount-field-row"> <text class="field-label">提现金额</text> <view class="amount-input-shell" :class="error.length > 0 ? 'field-invalid' : ''"> <text class="amount-prefix">¥</text> <input class="amount-input" v-model="amount" type="digit" maxlength="10" placeholder="请输入提现金额" placeholder-class="input-placeholder" @input="clearError" /> <input class="amount-input" v-model="amount" type="digit" maxlength="10" placeholder="请输入" placeholder-class="input-placeholder" @input="clearError" /> </view> </view> <text v-if="error.length > 0" class="field-error">{{error}}</text> @@ -17,18 +16,17 @@ <view class="field-block bank-field-block"> <view class="field-row bank-field-row"> <text class="field-label">提现银行卡</text> <view class="bank-value"> <view v-if="selected != null" class="bank-value"> <view v-if="selected != null" class="selected-bank-copy"> <text class="selected-bank-name">{{selected.bankName}}</text> <text class="selected-card-number">{{selected.cardMasked}}</text> </view> <text v-else class="bank-placeholder">请选择银行卡</text> </view> <view class="select-bank-button" @tap="chooseBank"><text>{{selected == null ? '选择' : '更换'}}</text></view> </view> </view> <view class="submit-button" :class="submitting ? 'submit-disabled' : ''" @tap="submit"><text>{{submitting ? '提交中' : '发起提现'}}</text></view> </view> <view class="submit-button" :class="submitting ? 'submit-disabled' : ''" @tap="submit"><text>{{submitting ? '提交中' : '发起提现'}}</text></view> <view class="safe-space"></view> </scroll-view> </view> @@ -101,4 +99,34 @@ .select-bank-button { width: 240rpx; height: 76rpx; margin: 18rpx 0 0; border-color: #F0D1B9; border-radius: 38rpx; color: #D97643; background-color: #FFF9F4; font-size: 28rpx; } .submit-button { width: 100%; height: 88rpx; margin: 62rpx 0 0; border-radius: 44rpx; color: #FFFFFF; background-image: linear-gradient(90deg, #FF7625 0%, #FF9630 100%); font-size: 29rpx; line-height: 41rpx; font-weight: 700; box-shadow: 0 12rpx 24rpx rgba(255, 107, 36, 0.20); } .safe-space { height: 70rpx; } /* Keep the withdrawal form aligned with the compact prototype layout. */ page { background-color: #FFFFFF; } .page { background-color: #FFFFFF; } .navigation-bar { height: 144rpx; padding: 64rpx 32rpx 0; background-color: #B7B7B7; align-items: center; } .back-button { left: 32rpx; top: 64rpx; width: 64rpx; height: 64rpx; } .back-icon { width: 40rpx; height: 40rpx; } .page-title { color: #FFFFFF; font-size: 30rpx; line-height: 42rpx; } .form-scroll { padding: 34rpx 26rpx 0; background-color: #FFFFFF; } .available-row { display: flex; height: 88rpx; padding: 0; flex-direction: row; justify-content: flex-start; align-items: center; } .available-label, .available-value { color: #777777; font-size: 27rpx; line-height: 38rpx; font-weight: 400; } .available-value { margin-left: 12rpx; } .form-card { padding: 0 20rpx; border-radius: 0; background-color: #FFFFFF; box-shadow: none; } .field-row { min-height: 158rpx; flex-direction: row; align-items: center; } .field-label, .amount-field-row .field-label, .bank-field-row .field-label { width: 142rpx; margin: 0; padding: 0; flex: none; color: #222222; font-size: 28rpx; line-height: 40rpx; font-weight: 400; text-align: left; } .amount-field-row { min-height: 158rpx; flex-direction: row; align-items: center; } .amount-input-shell { width: calc(100% - 142rpx); height: 104rpx; padding: 0 18rpx; flex: none; border: 1rpx solid #D7D7D7; border-radius: 5rpx; background-color: #FFFFFF; } .amount-prefix { color: #999999; font-size: 28rpx; } .amount-input { height: 102rpx; margin-left: 8rpx; color: #333333; font-size: 28rpx; } .input-placeholder { color: #999999; font-size: 28rpx; } .bank-field-block { margin-top: 0; } .bank-field-row { min-height: 158rpx; flex-direction: row; align-items: center; } .bank-value { min-width: 0; margin-right: 12rpx; flex: 1; } .selected-bank-copy { flex-direction: column; } .selected-bank-name { color: #333333; font-size: 26rpx; } .selected-card-number { margin-top: 2rpx; color: #888888; font-size: 23rpx; } .select-bank-button { width: 134rpx; height: 58rpx; padding: 0; margin: 0; border: 0; border-radius: 5rpx; color: #FFFFFF; background-color: #3478FF; font-size: 27rpx; font-weight: 400; } .submit-button { width: calc(100% - 40rpx); height: 80rpx; margin: 70rpx 0 0 20rpx; border-radius: 6rpx; color: #FFFFFF; background-color: #3478FF; background-image: none; font-size: 28rpx; line-height: 40rpx; font-weight: 400; box-shadow: none; } .field-error { margin-left: 142rpx; } .safe-space { height: 70rpx; } </style> talent-card-admin/src/layouts/AdminLayout.vue
@@ -83,7 +83,6 @@ const reservationMenus: MenuItem[] = [ { path: '/medical-reservations', label: '体检预约管理' }, { path: '/medical-applications', label: '就医申请管理' }, { path: '/parking-plates', label: '停车车牌管理' }, { path: '/fuel-services', label: '加油服务管理' }, { path: '/spouse-employment', label: '配偶就业管理' }, talent-card-admin/src/types/admin.ts
@@ -181,6 +181,7 @@ id: number | string merchantName: string merchantType?: string merchantTypeCode?: string contactName?: string contactMobile?: string logoUrl?: string talent-card-admin/src/views/MerchantCreateView.vue
@@ -80,35 +80,61 @@ const isEditMode = computed(() => route.query.mode === 'edit' && hasValidMerchantId.value) const hasExistingMerchant = computed(() => isEditMode.value) const normalizedMerchantType = computed(() => String(form.merchantType || '').trim()) const isFoodMerchant = computed(() => normalizedMerchantType.value === '餐饮服务') const isApartmentMerchant = computed(() => normalizedMerchantType.value === '公寓租赁') const isHotelMerchant = computed(() => normalizedMerchantType.value === '酒店服务') const isCarWashMerchant = computed(() => normalizedMerchantType.value === '自助洗车') const isHealthCheckMerchant = computed(() => normalizedMerchantType.value === '免费体检') const isParkingMerchant = computed(() => normalizedMerchantType.value === '停车服务') const isFuelMerchant = computed(() => normalizedMerchantType.value === '加油服务') const isChildcareMerchant = computed(() => normalizedMerchantType.value === '子女托管') const isFinancialMerchant = computed(() => normalizedMerchantType.value === '金融服务') const merchantTypeAliases: Record<string, string> = { '餐饮服务': 'food', food: 'food', '景区服务': 'scenic', scenic: 'scenic', '酒店服务': 'hotel', hotel: 'hotel', '公寓租赁': 'apartment', apartment: 'apartment', '自助洗车': 'carWash', '自助洗车服务': 'carWash', carWash: 'carWash', '免费体检': 'medical', medical: 'medical', '停车服务': 'parking', parking: 'parking', '加油服务': 'fuel', fuel: 'fuel', '子女托管': 'children', children: 'children', '金融服务': 'finance', finance: 'finance', '配偶推荐就业': 'employment', employment: 'employment', '行政审批': 'approval', approval: 'approval', '观影服务': 'cinema', cinema: 'cinema', theatre: 'cinema', '电影院': 'cinema', '影院': 'cinema', '影城': 'cinema', '剧院': 'cinema', '购房优惠': 'housing', housing: 'housing', '购车服务': 'car', car: 'car', '家电服务': 'appliance', appliance: 'appliance', '数码服务': 'digital', digital: 'digital', '文化服务': 'culture', culture: 'culture', book: 'culture', '电信服务': 'telecom', telecom: 'telecom', '口腔治疗保健': 'dental', dental: 'dental', } const merchantTypeCode = computed(() => { const raw = String(form.merchantTypeCode || normalizedMerchantType.value).trim() return merchantTypeAliases[raw] || raw }) const isFoodMerchant = computed(() => merchantTypeCode.value === 'food') const isApartmentMerchant = computed(() => merchantTypeCode.value === 'apartment') const isHotelMerchant = computed(() => merchantTypeCode.value === 'hotel') const isCarWashMerchant = computed(() => merchantTypeCode.value === 'carWash') const isHealthCheckMerchant = computed(() => merchantTypeCode.value === 'medical') const isParkingMerchant = computed(() => merchantTypeCode.value === 'parking') const isFuelMerchant = computed(() => merchantTypeCode.value === 'fuel') const isChildcareMerchant = computed(() => merchantTypeCode.value === 'children') const isFinancialMerchant = computed(() => merchantTypeCode.value === 'finance') const isMovieMerchant = computed(() => [ '观影服务', 'cinema', 'theatre', '电影院', '影院', '影城', '剧院', ].includes(normalizedMerchantType.value)) const isSpouseEmploymentMerchant = computed(() => normalizedMerchantType.value === '配偶推荐就业') const isApprovalMerchant = computed(() => normalizedMerchantType.value === '行政审批') const isServiceMerchant = computed(() => isFoodMerchant.value || normalizedMerchantType.value === '景区服务') 'cinema', ].includes(merchantTypeCode.value)) const isSpouseEmploymentMerchant = computed(() => merchantTypeCode.value === 'employment') const isApprovalMerchant = computed(() => merchantTypeCode.value === 'approval') const isServiceMerchant = computed(() => isFoodMerchant.value || merchantTypeCode.value === 'scenic') const supportsStoreConsumption = computed(() => [ '酒店服务', '景区服务', '餐饮服务', '口腔治疗保健', '免费体检', ].includes(normalizedMerchantType.value) || (isCarWashMerchant.value && form.miniProgramJumpType === 'normal')) 'hotel', 'scenic', 'food', 'dental', 'medical', ].includes(merchantTypeCode.value) || (isCarWashMerchant.value && form.miniProgramJumpType === 'normal')) const merchantAppLoginOptionalTypes = [ '购房优惠', '购车服务', '家电服务', '数码服务', '文化服务', '电信服务', '口腔治疗保健', '加油服务', 'housing', 'car', 'appliance', 'digital', 'culture', 'telecom', 'dental', 'fuel', ] const simplifiedMerchantSettingsTypes = [ '购房优惠', '购车服务', '家电服务', '数码服务', '文化服务', '电信服务', '口腔治疗保健', '加油服务', 'housing', 'car', 'appliance', 'digital', 'culture', 'telecom', 'dental', 'fuel', ] const usesSimplifiedMerchantSettings = computed(() => simplifiedMerchantSettingsTypes.includes(normalizedMerchantType.value)) const usesSimplifiedMerchantSettings = computed(() => simplifiedMerchantSettingsTypes.includes(merchantTypeCode.value)) const settingsAndRightsOnlyMerchantTypes = [ '加油服务', '购房优惠', '购车服务', '家电服务', '数码服务', '文化服务', '电信服务', 'fuel', 'housing', 'car', 'appliance', 'digital', 'culture', 'telecom', ] const usesSettingsAndRightsOnlyTabs = computed(() => settingsAndRightsOnlyMerchantTypes.includes(normalizedMerchantType.value)) const usesSettingsAndRightsOnlyTabs = computed(() => settingsAndRightsOnlyMerchantTypes.includes(merchantTypeCode.value)) const supportsMerchantAppLogin = computed(() => ( isServiceMerchant.value || isApartmentMerchant.value @@ -121,10 +147,10 @@ || isMovieMerchant.value || isSpouseEmploymentMerchant.value || isApprovalMerchant.value || merchantAppLoginOptionalTypes.includes(normalizedMerchantType.value) || merchantAppLoginOptionalTypes.includes(merchantTypeCode.value) )) const requiresMerchantOperator = computed(() => (!isEditMode.value || !merchantHasLoginAccount.value) && ( normalizedMerchantType.value === '景区服务' merchantTypeCode.value === 'scenic' || (supportsMerchantAppLogin.value && Number(form.canLoginMerchantApp) === 1) )) function carWashJumpMeta() { @@ -167,7 +193,8 @@ function defaultMerchantRecommend() { const merchantType = queryString('merchantType') return merchantType === '餐饮服务' || merchantType === '景区服务' ? 1 : 0 const merchantTypeCode = merchantTypeAliases[merchantType] || merchantType return merchantTypeCode === 'food' || merchantTypeCode === 'scenic' ? 1 : 0 } function applyNewMerchantDefaults() { @@ -175,7 +202,9 @@ const merchantType = queryString('merchantType') form.merchantType = merchantType form.recommend = merchantType === '餐饮服务' || merchantType === '景区服务' ? 1 : 0 form.merchantTypeCode = '' const merchantTypeCode = merchantTypeAliases[merchantType] || merchantType form.recommend = merchantTypeCode === 'food' || merchantTypeCode === 'scenic' ? 1 : 0 form.sortNo = undefined } @@ -227,7 +256,7 @@ ] }) const form = reactive<MerchantPayload & { createdAt: string }>({ const form = reactive<MerchantPayload & { createdAt: string; merchantTypeCode?: string }>({ merchantName: '', merchantType: queryString('merchantType', ''), contactMobile: '', @@ -548,18 +577,18 @@ const businessHours = reactive<BusinessHour[]>([{ id: 1, value: [] }]) function defaultMerchantRights(): MerchantRightConfig[] { const currentType = queryString('merchantType', '') || normalizedMerchantType.value const supportsDefaultStoreConsumption = ['餐饮服务', '景区服务', '口腔治疗保健', '免费体检'].includes(currentType) || (currentType === '自助洗车' && form.miniProgramJumpType === 'normal') const isHotel = currentType === '酒店服务' const isCarWash = currentType === '自助洗车' const isHealthCheck = currentType === '免费体检' const isParking = currentType === '停车服务' const isChildcare = currentType === '子女托管' const isFinancial = currentType === '金融服务' const isMovie = currentType === '观影服务' const isSpouseEmployment = currentType === '配偶推荐就业' const isApproval = currentType === '行政审批' const currentType = merchantTypeCode.value const supportsDefaultStoreConsumption = ['food', 'scenic', 'dental', 'medical'].includes(currentType) || (currentType === 'carWash' && form.miniProgramJumpType === 'normal') const isHotel = currentType === 'hotel' const isCarWash = currentType === 'carWash' const isHealthCheck = currentType === 'medical' const isParking = currentType === 'parking' const isChildcare = currentType === 'children' const isFinancial = currentType === 'finance' const isMovie = currentType === 'cinema' const isSpouseEmployment = currentType === 'employment' const isApproval = currentType === 'approval' if (isHealthCheck) { return [ talent-card-admin/src/views/RoleFormView.vue
@@ -38,11 +38,8 @@ { name: '预约管理', pages: [ { code: 'appointment-management', name: '预约服务管理', actions: ['查看', '审核', '下载'] }, { code: 'medical-reservations', name: '体检预约管理', actions: ['查看', '审核', '下载'] }, { code: 'medical-applications', name: '就医申请管理', actions: ['查看', '审核', '下载'] }, { code: 'parking-plates', name: '停车车牌管理', actions: ['查看', '审核', '下载'] }, { code: 'car-wash-benefits', name: '洗车权益管理', actions: ['查看', '审核'] }, { code: 'fuel-services', name: '加油服务管理', actions: ['查看', '审核', '下载'] }, { code: 'spouse-employment', name: '配偶就业管理', actions: ['查看', '审核', '下载'] }, { code: 'hotel-reservations', name: '酒店预约管理', actions: ['查看', '审核', '下载'] }, talent-card-admin/src/views/StaffManagementView.vue
@@ -48,7 +48,7 @@ { required: true, message: "请输入登录账号", trigger: "blur" }, { validator: (_rule, value, callback) => { if (!editId.value && value && !accountPattern.test(String(value).trim())) { if (value && !accountPattern.test(String(value).trim())) { callback(new Error("登录账号仅支持英文、数字或英文+数字")); return; } @@ -116,8 +116,8 @@ const keepMobileDigits = () => { form.mobile = form.mobile.replace(/\D/g, "").slice(0, 11); }; const normalizeAccount = () => { form.account = form.account.replace(/[^A-Za-z0-9]/g, "").slice(0, 32); const normalizeAccount = (value: string) => { form.account = String(value || "").replace(/[^A-Za-z0-9]/g, "").slice(0, 32); accountTaken.value = false; }; async function checkAccountAvailable() { @@ -344,11 +344,11 @@ @input="keepMobileDigits" /></el-form-item ><el-form-item label="登录账号" prop="account" required :error="accountTaken ? '登录账号已存在,请更换' : ''" ><el-input v-model="form.account" :model-value="form.account" :disabled="Boolean(editId)" maxlength="32" placeholder="仅支持英文和数字" @input="normalizeAccount" @update:model-value="normalizeAccount" @blur="checkAccountAvailable" /></el-form-item ><el-form-item label="登录密码" prop="password" :required="!editId" ><el-input @@ -357,7 +357,7 @@ :placeholder=" editId ? '留空则不修改' : '至少 6 位' " /></el-form-item ><el-form-item v-if="!editId || form.password" label="确认密码" prop="confirmPassword" :required="!editId || Boolean(form.password)" ><el-form-item label="确认密码" prop="confirmPassword" :required="!editId || Boolean(form.password)" ><el-input v-model="form.confirmPassword" type="password"