From 8394da7ecba51564491cb3dfbd156ec92f33607b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E6=9D=8E=E4=BC=8A=E5=B8=86?= Date: Wed, 16 Sep 2026 15:21:41 +0800 Subject: [PATCH] =?UTF-8?q?feat:=E4=B8=AA=E4=BA=BA=E4=B8=AD=E5=BF=83?= =?UTF-8?q?=E5=AE=8C=E6=88=90?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/components/BottomSheet.scss | 46 +++ src/components/BottomSheet.vue | 65 +++ src/constants/address.ts | 20 + src/constants/contract.ts | 53 +++ src/constants/invoice-list.ts | 31 ++ src/constants/invoice.ts | 47 +++ src/constants/personal-center.ts | 14 +- src/constants/qualification.ts | 38 ++ src/hooks/use-invoice-headers.ts | 16 + src/hooks/use-qualifications.ts | 16 + src/pages.json | 42 ++ src/pages/contract-center/index.scss | 229 +++++++++++ src/pages/contract-center/index.vue | 178 ++++++++ src/pages/home-index/index.vue | 8 +- src/pages/personal-center/address/index.scss | 209 ++++++++++ src/pages/personal-center/address/index.vue | 284 +++++++++++++ src/pages/personal-center/index.vue | 11 - .../personal-center/invoice-list/index.scss | 254 ++++++++++++ .../personal-center/invoice-list/index.vue | 290 +++++++++++++ src/pages/personal-center/invoice/index.scss | 238 +++++++++++ src/pages/personal-center/invoice/index.vue | 175 ++++++++ .../qualification-list/index.scss | 131 ++++++ .../qualification-list/index.vue | 131 ++++++ .../qualification-upload/index.scss | 248 +++++++++++ .../qualification-upload/index.vue | 384 ++++++++++++++++++ .../service-hotline/index.scss | 94 +++++ .../personal-center/service-hotline/index.vue | 75 ++++ src/static/icon/service-hotline.svg | 1 + src/types/address.ts | 8 + src/types/contract.ts | 23 ++ src/types/invoice-list.ts | 9 + src/types/invoice.ts | 14 + src/types/qualification.ts | 12 + src/utils/quick-entry-navigate.ts | 39 ++ 34 files changed, 3415 insertions(+), 18 deletions(-) create mode 100644 src/components/BottomSheet.scss create mode 100644 src/components/BottomSheet.vue create mode 100644 src/constants/address.ts create mode 100644 src/constants/contract.ts create mode 100644 src/constants/invoice-list.ts create mode 100644 src/constants/invoice.ts create mode 100644 src/constants/qualification.ts create mode 100644 src/hooks/use-invoice-headers.ts create mode 100644 src/hooks/use-qualifications.ts create mode 100644 src/pages/contract-center/index.scss create mode 100644 src/pages/contract-center/index.vue create mode 100644 src/pages/personal-center/address/index.scss create mode 100644 src/pages/personal-center/address/index.vue create mode 100644 src/pages/personal-center/invoice-list/index.scss create mode 100644 src/pages/personal-center/invoice-list/index.vue create mode 100644 src/pages/personal-center/invoice/index.scss create mode 100644 src/pages/personal-center/invoice/index.vue create mode 100644 src/pages/personal-center/qualification-list/index.scss create mode 100644 src/pages/personal-center/qualification-list/index.vue create mode 100644 src/pages/personal-center/qualification-upload/index.scss create mode 100644 src/pages/personal-center/qualification-upload/index.vue create mode 100644 src/pages/personal-center/service-hotline/index.scss create mode 100644 src/pages/personal-center/service-hotline/index.vue create mode 100644 src/static/icon/service-hotline.svg create mode 100644 src/types/address.ts create mode 100644 src/types/contract.ts create mode 100644 src/types/invoice-list.ts create mode 100644 src/types/invoice.ts create mode 100644 src/types/qualification.ts create mode 100644 src/utils/quick-entry-navigate.ts diff --git a/src/components/BottomSheet.scss b/src/components/BottomSheet.scss new file mode 100644 index 0000000..fa065c3 --- /dev/null +++ b/src/components/BottomSheet.scss @@ -0,0 +1,46 @@ +@import '@/styles/variables.scss'; + +.bottom-sheet { + position: fixed; + top: 0; + right: 0; + bottom: 0; + left: 0; + z-index: 300; + display: flex; + flex-direction: column; + justify-content: flex-end; +} + +.bottom-sheet__mask { + position: absolute; + top: 0; + right: 0; + bottom: 0; + left: 0; + background: rgba(0, 0, 0, 0.45); + opacity: 0; + transition: opacity 0.3s ease; +} + +.bottom-sheet__mask--active { + opacity: 1; +} + +.bottom-sheet__panel { + position: relative; + z-index: 1; + padding-bottom: env(safe-area-inset-bottom); + background: $color-bg-page; + border-radius: 24rpx 24rpx 0 0; + transform: translateY(100%); + transition: transform 0.3s cubic-bezier(0.25, 0.8, 0.25, 1); +} + +.bottom-sheet__panel--active { + transform: translateY(0); +} + +.bottom-sheet__body { + padding: 32rpx; +} diff --git a/src/components/BottomSheet.vue b/src/components/BottomSheet.vue new file mode 100644 index 0000000..cb27efb --- /dev/null +++ b/src/components/BottomSheet.vue @@ -0,0 +1,65 @@ + + + + + diff --git a/src/constants/address.ts b/src/constants/address.ts new file mode 100644 index 0000000..c2994df --- /dev/null +++ b/src/constants/address.ts @@ -0,0 +1,20 @@ +import type { AddressItem } from '@/types/address' + +export const ADDRESS_LIST: AddressItem[] = [ + { + id: '1', + name: '张三', + phone: '15588888000', + region: '山东省日照市东港区', + detail: '科技园南路99号', + isDefault: true, + }, + { + id: '2', + name: '张三', + phone: '15588888000', + region: '山东省日照市东港区', + detail: '科技园南路99号', + isDefault: false, + }, +] diff --git a/src/constants/contract.ts b/src/constants/contract.ts new file mode 100644 index 0000000..a7ab1f6 --- /dev/null +++ b/src/constants/contract.ts @@ -0,0 +1,53 @@ +import type { ContractItem, ContractTab } from '@/types/contract' + +export const CONTRACT_TABS: Array<{ value: ContractTab, label: string }> = [ + { value: 'all', label: '全部' }, + { value: 'pending', label: '待签署' }, + { value: 'signed', label: '已签署' }, +] + +export const CONTRACT_LIST: ContractItem[] = [ + { + id: '1', + contractNo: 'C8K2M202408001', + title: '社区康养智慧系统', + type: '软件开发', + relatedLabel: '关联合同', + relatedValue: '20260814ZZZ151245', + signStatus: 'signed', + badges: [ + { type: 'signed', label: '已签署' }, + { type: 'in_progress', label: '履行中' }, + ], + showDownload: true, + showSign: false, + }, + { + id: '2', + contractNo: 'C8K2M202408001', + title: '社区康养智慧系统', + type: '软件开发', + relatedLabel: '关联项目', + relatedValue: '社区康养智慧系统', + signStatus: 'pending', + badges: [ + { type: 'pending_sign', label: '待签署' }, + ], + showDownload: false, + showSign: true, + }, + { + id: '3', + contractNo: 'C8K2M202408001', + title: '社区康养智慧系统', + type: '软件开发', + relatedLabel: '关联项目', + relatedValue: '社区康养智慧系统', + signStatus: 'signed', + badges: [ + { type: 'signed', label: '已签署' }, + ], + showDownload: false, + showSign: false, + }, +] diff --git a/src/constants/invoice-list.ts b/src/constants/invoice-list.ts new file mode 100644 index 0000000..1cd0634 --- /dev/null +++ b/src/constants/invoice-list.ts @@ -0,0 +1,31 @@ +import type { InvoiceHeaderItem } from '@/types/invoice-list' + +export const INVOICE_HEADER_LIST: InvoiceHeaderItem[] = [ + { + id: '1', + title: '山东日照有限公司', + type: 'enterprise', + taxNo: '344683434513543543545535', + isDefault: true, + }, + { + id: '2', + title: '山东日照有限公司', + type: 'personal', + taxNo: '344683434513543543545535', + isDefault: false, + }, +] + +export const INVOICE_HEADER_TYPE_LABEL: Record = { + enterprise: '企业', + personal: '个人', +} + +export const INVOICE_HEADER_FORM_TYPE_OPTIONS: Array<{ + value: InvoiceHeaderItem['type'] + label: string +}> = [ + { value: 'enterprise', label: '企业单位' }, + { value: 'personal', label: '非企业单位' }, +] diff --git a/src/constants/invoice.ts b/src/constants/invoice.ts new file mode 100644 index 0000000..d22affa --- /dev/null +++ b/src/constants/invoice.ts @@ -0,0 +1,47 @@ +import type { InvoiceRecordItem, InvoiceRecordStatus } from '@/types/invoice' + +export const INVOICE_RECORD_TABS: Array<{ value: InvoiceRecordStatus, label: string }> = [ + { value: 'all', label: '全部' }, + { value: 'invoiced', label: '已开票' }, + { value: 'not_invoiced', label: '未开票' }, + { value: 'invoicing', label: '开票中' }, +] + +export const INVOICE_RECORD_STATUS_LABEL: Record = { + invoiced: '已开票', + not_invoiced: '未开票', + invoicing: '开票中', +} + +export const INVOICE_RECORD_LIST: InvoiceRecordItem[] = [ + { + id: '1', + title: '第一期·预付款', + ratio: '比例33%', + amount: 20100, + transactionNo: 'T20260819153035678K2M001', + relatedProject: '社区康养智慧系统', + invoiceTime: '2026-08-14 15:00', + status: 'invoiced', + }, + { + id: '2', + title: '第一期·预付款', + ratio: '比例33%', + amount: 20100, + transactionNo: 'T20260819153035678K2M002', + relatedProject: '社区康养智慧系统', + invoiceTime: '2026-08-14 15:00', + status: 'invoiced', + }, + { + id: '3', + title: '第一期·预付款', + ratio: '比例33%', + amount: 20100, + transactionNo: 'T20260819153035678K2M003', + relatedProject: '社区康养智慧系统', + invoiceTime: '2026-08-14 15:00', + status: 'not_invoiced', + }, +] diff --git a/src/constants/personal-center.ts b/src/constants/personal-center.ts index 960fb13..0539a44 100644 --- a/src/constants/personal-center.ts +++ b/src/constants/personal-center.ts @@ -11,7 +11,7 @@ import iconInvoice from '@/static/icon/invoice.png' import iconMessagePush from '@/static/icon/message-push.png' import iconQualification from '@/static/icon/qualification.png' import iconSecurity from '@/static/icon/security.png' -import iconServiceHotline from '@/static/icon/service-hotline.png' +import iconServiceHotline from '@/static/icon/service-hotline.svg' export const PERSONAL_CENTER_PROFILE: PersonalCenterProfile = { nickname: '这里是昵称', @@ -23,15 +23,17 @@ export const PERSONAL_CENTER_MENU: PersonalCenterMenuItem[] = [ { key: 'security', label: '账号安全', icon: iconSecurity, path: '/pages/personal-center/account-security/index' }, { key: 'message-push', label: '消息推送', icon: iconMessagePush }, { key: 'feedback', label: '意见反馈', icon: iconFeedback, path: '/pages/personal-center/feedback/index' }, - { key: 'contract-list', label: '合同列表', icon: iconContractList }, + { key: 'contract-list', label: '合同列表', icon: iconContractList, path: '/pages/contract-center/index' }, { key: 'finance', label: '财务中心', icon: iconFinance, path: '/pages/personal-center/finance/index' }, - { key: 'invoice', label: '发票列表', icon: iconInvoice }, - { key: 'address', label: '地址管理', icon: iconAddress }, + { key: 'invoice', label: '发票列表', icon: iconInvoice, path: '/pages/personal-center/invoice/index' }, + { key: 'address', label: '地址管理', icon: iconAddress, path: '/pages/personal-center/address/index' }, { key: 'favorites', label: '收藏列表', icon: iconFavorites, path: '/pages/case-library/favorites/index' }, - { key: 'qualification', label: '资质列表', icon: iconQualification }, + { key: 'qualification', label: '资质列表', icon: iconQualification, path: '/pages/personal-center/qualification-list/index' }, { key: 'help', label: '帮助中心', icon: iconHelp }, { key: 'about', label: '关于我们', icon: iconAbout }, - { key: 'service-hotline', label: '专属客服热线', icon: iconServiceHotline }, + { key: 'service-hotline', label: '专属客服热线', icon: iconServiceHotline, path: '/pages/personal-center/service-hotline/index' }, ] export const PERSONAL_CENTER_SERVICE_HOTLINE = '400-000-0000' + +export const PERSONAL_CENTER_SERVICE_HOTLINE_HOURS = '工作日 8:00-12:00 14:00-18:00' diff --git a/src/constants/qualification.ts b/src/constants/qualification.ts new file mode 100644 index 0000000..cf5a28d --- /dev/null +++ b/src/constants/qualification.ts @@ -0,0 +1,38 @@ +import type { QualificationItem, QualificationStatus } from '@/types/qualification' + +export const QUALIFICATION_TYPE_OPTIONS = [ + '营业执照', + '高新技术企业证书', + 'ISO 质量管理体系认证', + '软件企业认定证书', +] + +export const QUALIFICATION_STATUS_LABEL: Record = { + reviewing: '审核中', + approved: '已通过', + rejected: '已驳回', + draft: '草稿', +} + +export const QUALIFICATION_LIST: QualificationItem[] = [ + { + id: '1', + type: '营业执照', + certificateName: '山东日照有限公司', + certificateNo: '344683434513543543545535', + issuer: '山东省政务局', + validFrom: '2024-10-10', + validTo: '2027-10-10', + status: 'reviewing', + }, + { + id: '2', + type: '营业执照', + certificateName: '山东日照有限公司', + certificateNo: '344683434513543543545535', + issuer: '山东省政务局', + validFrom: '2024-10-10', + validTo: '2027-10-10', + status: 'reviewing', + }, +] diff --git a/src/hooks/use-invoice-headers.ts b/src/hooks/use-invoice-headers.ts new file mode 100644 index 0000000..bd22e09 --- /dev/null +++ b/src/hooks/use-invoice-headers.ts @@ -0,0 +1,16 @@ +import { computed, ref } from 'vue' +import { INVOICE_HEADER_LIST } from '@/constants/invoice-list' +import type { InvoiceHeaderItem } from '@/types/invoice-list' + +const invoiceHeaders = ref(INVOICE_HEADER_LIST.map(item => ({ ...item }))) + +export function useInvoiceHeaders() { + const defaultHeader = computed(() => + invoiceHeaders.value.find(item => item.isDefault) || invoiceHeaders.value[0] || null, + ) + + return { + invoiceHeaders, + defaultHeader, + } +} diff --git a/src/hooks/use-qualifications.ts b/src/hooks/use-qualifications.ts new file mode 100644 index 0000000..04c1941 --- /dev/null +++ b/src/hooks/use-qualifications.ts @@ -0,0 +1,16 @@ +import { ref } from 'vue' +import { QUALIFICATION_LIST } from '@/constants/qualification' +import type { QualificationItem } from '@/types/qualification' + +const qualifications = ref(QUALIFICATION_LIST.map(item => ({ ...item }))) + +export function useQualifications() { + function getQualificationById(id: string) { + return qualifications.value.find(item => item.id === id) || null + } + + return { + qualifications, + getQualificationById, + } +} diff --git a/src/pages.json b/src/pages.json index 84dd4bf..60e8582 100644 --- a/src/pages.json +++ b/src/pages.json @@ -198,6 +198,48 @@ "style": { "navigationStyle": "custom" } + }, + { + "path": "pages/personal-center/invoice/index", + "style": { + "navigationStyle": "custom" + } + }, + { + "path": "pages/personal-center/invoice-list/index", + "style": { + "navigationStyle": "custom" + } + }, + { + "path": "pages/personal-center/address/index", + "style": { + "navigationStyle": "custom" + } + }, + { + "path": "pages/contract-center/index", + "style": { + "navigationStyle": "custom" + } + }, + { + "path": "pages/personal-center/service-hotline/index", + "style": { + "navigationStyle": "custom" + } + }, + { + "path": "pages/personal-center/qualification-list/index", + "style": { + "navigationStyle": "custom" + } + }, + { + "path": "pages/personal-center/qualification-upload/index", + "style": { + "navigationStyle": "custom" + } } ], "globalStyle": { diff --git a/src/pages/contract-center/index.scss b/src/pages/contract-center/index.scss new file mode 100644 index 0000000..22d66ca --- /dev/null +++ b/src/pages/contract-center/index.scss @@ -0,0 +1,229 @@ +@import '@/styles/variables.scss'; + +.contract-center { + display: flex; + flex-direction: column; + min-height: 100vh; + background: $color-bg-section; +} + +.contract-center__header { + display: flex; + align-items: center; + justify-content: space-between; + flex-shrink: 0; + padding: calc(var(--status-bar-height, 44px) + 60rpx) 24rpx 20rpx; + background: $color-bg-page; +} + +.contract-center__back { + display: flex; + align-items: center; + justify-content: center; + width: 64rpx; + height: 64rpx; +} + +.contract-center__back-icon { + width: 40rpx; + height: 40rpx; +} + +.contract-center__title { + font-size: 34rpx; + font-weight: 600; + color: $color-text-primary; +} + +.contract-center__header-placeholder { + width: 64rpx; + height: 64rpx; +} + +.contract-center__toolbar { + flex-shrink: 0; + padding: 0 24rpx 24rpx; + background: $color-bg-page; +} + +.contract-center__search { + display: flex; + align-items: center; + height: 72rpx; + padding: 0 24rpx; + background: $color-bg-section; + border-radius: 36rpx; +} + +.contract-center__search-icon { + flex-shrink: 0; + width: 32rpx; + height: 32rpx; + margin-right: 12rpx; +} + +.contract-center__search-input { + flex: 1; + font-size: 26rpx; + color: $color-text-primary; +} + +.contract-center__search-placeholder { + color: $color-text-placeholder; +} + +.contract-center__tabs { + display: flex; + margin-top: 24rpx; + overflow: hidden; + border: 2rpx solid $color-primary; + border-radius: 12rpx; +} + +.contract-center__tab { + display: flex; + flex: 1; + align-items: center; + justify-content: center; + height: 72rpx; + background: $color-bg-page; + border-right: 2rpx solid $color-primary; + + &:last-child { + border-right: none; + } + + &--active { + background: $color-primary; + } +} + +.contract-center__tab-text { + font-size: 28rpx; + color: $color-primary; +} + +.contract-center__tab--active .contract-center__tab-text { + font-weight: 600; + color: #ffffff; +} + +.contract-center__scroll { + flex: 1; + height: 0; +} + +.contract-center__list { + padding: 0 24rpx calc(32rpx + env(safe-area-inset-bottom)); +} + +.contract-center__card { + padding: 28rpx 24rpx; + margin-top: 24rpx; + background: $color-bg-page; + border-radius: 20rpx; + box-shadow: 0 8rpx 24rpx rgba(0, 0, 0, 0.04); +} + +.contract-center__card-top { + display: flex; + align-items: flex-start; + justify-content: space-between; + gap: 16rpx; +} + +.contract-center__contract-no { + flex: 1; + min-width: 0; + font-size: 22rpx; + color: $color-text-secondary; +} + +.contract-center__badges { + display: flex; + flex-shrink: 0; + gap: 12rpx; +} + +.contract-center__badge { + padding: 4rpx 12rpx; + font-size: 20rpx; + border-radius: 6rpx; + + &--signed { + color: #16a34a; + background: #ecfdf3; + } + + &--in_progress { + color: $color-primary; + background: $color-primary-light; + } + + &--pending_sign { + color: $color-stat-orange; + background: $color-stat-orange-bg; + } +} + +.contract-center__title-row { + display: flex; + align-items: center; + justify-content: space-between; + gap: 16rpx; + margin-top: 20rpx; +} + +.contract-center__card-title { + flex: 1; + min-width: 0; + font-size: 30rpx; + font-weight: 600; + color: $color-text-primary; +} + +.contract-center__detail-link { + flex-shrink: 0; + font-size: 24rpx; + color: $color-text-secondary; +} + +.contract-center__related { + display: block; + margin-top: 12rpx; + font-size: 24rpx; + color: $color-text-secondary; +} + +.contract-center__actions { + display: flex; + gap: 20rpx; + margin-top: 28rpx; + + &--single { + .contract-center__action-btn { + flex: 1; + } + } +} + +.contract-center__action-btn { + display: flex; + flex: 1; + align-items: center; + justify-content: center; + height: 80rpx; + font-size: 28rpx; + border-radius: 12rpx; + + &--outline { + color: $color-text-primary; + background: $color-bg-page; + border: 1rpx solid #d8dde6; + } + + &--primary { + color: #ffffff; + background: $color-primary; + } +} diff --git a/src/pages/contract-center/index.vue b/src/pages/contract-center/index.vue new file mode 100644 index 0000000..21b6324 --- /dev/null +++ b/src/pages/contract-center/index.vue @@ -0,0 +1,178 @@ + + + + + diff --git a/src/pages/home-index/index.vue b/src/pages/home-index/index.vue index 114f0e5..a752e5b 100644 --- a/src/pages/home-index/index.vue +++ b/src/pages/home-index/index.vue @@ -2,7 +2,8 @@ import AppTabBar from '@/components/AppTabBar.vue' import { useGreeting } from '@/hooks/use-greeting' import { useQuickEntries } from '@/hooks/use-quick-entries' -import type { ProjectItem, ServiceItem } from '@/types/home' +import type { ProjectItem, QuickEntryItem, ServiceItem } from '@/types/home' +import { navigateQuickEntry } from '@/utils/quick-entry-navigate' import headerBg from '@/static/icons/1.png' import softwareIllus from '@/static/icons/software.png' import hardwareIllus from '@/static/icons/hardware.png' @@ -56,6 +57,10 @@ const services: ServiceItem[] = [ }, ] +function handleQuickEntryTap(entry: QuickEntryItem) { + navigateQuickEntry(entry.id, entry.label) +} + const projects: ProjectItem[] = [ { id: '1', @@ -163,6 +168,7 @@ const projects: ProjectItem[] = [ v-for="entry in pinnedEntries" :key="entry.id" class="home__quick-item" + @tap="handleQuickEntryTap(entry)" > +import { computed, ref } from 'vue' +import BottomSheet from '@/components/BottomSheet.vue' +import { ADDRESS_LIST } from '@/constants/address' +import type { AddressItem } from '@/types/address' +import { navigateBackWithFallback } from '@/utils/navigate-back' + +const addressList = ref(ADDRESS_LIST.map(item => ({ ...item }))) +const sheetVisible = ref(false) +const editingId = ref(null) +const formName = ref('') +const formPhone = ref('') +const formRegion = ref('') +const formDetail = ref('') + +const isEditing = computed(() => editingId.value !== null) +const sheetTitle = computed(() => (isEditing.value ? '编辑地址' : '新增地址')) +const sheetSubmitText = computed(() => (isEditing.value ? '保存' : '+ 新增地址')) + +function formatAddress(item: AddressItem) { + return `${item.region}${item.detail}` +} + +function handleBack() { + navigateBackWithFallback('/pages/personal-center/index') +} + +function handleSetDefault(item: AddressItem) { + addressList.value = addressList.value.map(row => ({ + ...row, + isDefault: row.id === item.id, + })) +} + +function handleEdit(item: AddressItem) { + editingId.value = item.id + formName.value = item.name + formPhone.value = item.phone + formRegion.value = item.region + formDetail.value = item.detail + sheetVisible.value = true +} + +function handleDelete(item: AddressItem) { + uni.showModal({ + title: '删除地址', + content: `确认删除「${item.name}」的地址吗?`, + confirmText: '删除', + confirmColor: '#2563EB', + success: (res) => { + if (!res.confirm) + return + + addressList.value = addressList.value.filter(row => row.id !== item.id) + if (addressList.value.length && !addressList.value.some(row => row.isDefault)) + addressList.value[0].isDefault = true + + uni.showToast({ title: '已删除', icon: 'none' }) + }, + }) +} + +function resetForm() { + editingId.value = null + formName.value = '' + formPhone.value = '' + formRegion.value = '' + formDetail.value = '' +} + +function handleAdd() { + resetForm() + sheetVisible.value = true +} + +function closeSheet() { + sheetVisible.value = false + editingId.value = null +} + +function handleSubmit() { + if (!formName.value.trim()) { + uni.showToast({ title: '请输入收货人姓名', icon: 'none' }) + return + } + if (!formPhone.value.trim()) { + uni.showToast({ title: '请输入联系电话', icon: 'none' }) + return + } + if (!formRegion.value.trim()) { + uni.showToast({ title: '请输入所在地区', icon: 'none' }) + return + } + if (!formDetail.value.trim()) { + uni.showToast({ title: '请输入详细地址', icon: 'none' }) + return + } + + const payload = { + name: formName.value.trim(), + phone: formPhone.value.trim(), + region: formRegion.value.trim(), + detail: formDetail.value.trim(), + } + + if (editingId.value) { + addressList.value = addressList.value.map(row => ( + row.id === editingId.value + ? { ...row, ...payload } + : row + )) + closeSheet() + uni.showToast({ title: '保存成功', icon: 'none' }) + return + } + + const isFirst = addressList.value.length === 0 + addressList.value.push({ + id: `${Date.now()}`, + ...payload, + isDefault: isFirst, + }) + + closeSheet() + uni.showToast({ title: '新增成功', icon: 'none' }) +} + + + + + diff --git a/src/pages/personal-center/index.vue b/src/pages/personal-center/index.vue index 170d302..b20ab87 100644 --- a/src/pages/personal-center/index.vue +++ b/src/pages/personal-center/index.vue @@ -3,7 +3,6 @@ import AppTabBar from '@/components/AppTabBar.vue' import { PERSONAL_CENTER_MENU, PERSONAL_CENTER_PROFILE, - PERSONAL_CENTER_SERVICE_HOTLINE, } from '@/constants/personal-center' import type { PersonalCenterMenuItem } from '@/types/personal-center' import editIcon from '@/static/icon/edit.svg' @@ -21,16 +20,6 @@ function handleMenuTap(item: PersonalCenterMenuItem) { return } - if (item.key === 'service-hotline') { - uni.makePhoneCall({ - phoneNumber: PERSONAL_CENTER_SERVICE_HOTLINE.replace(/-/g, ''), - fail: () => { - uni.showToast({ title: PERSONAL_CENTER_SERVICE_HOTLINE, icon: 'none' }) - }, - }) - return - } - uni.showToast({ title: '功能开发中', icon: 'none' }) } diff --git a/src/pages/personal-center/invoice-list/index.scss b/src/pages/personal-center/invoice-list/index.scss new file mode 100644 index 0000000..249cf81 --- /dev/null +++ b/src/pages/personal-center/invoice-list/index.scss @@ -0,0 +1,254 @@ +@import '@/styles/variables.scss'; + +.invoice-list { + display: flex; + flex-direction: column; + min-height: 100vh; + background: $color-bg-section; +} + +.invoice-list__navbar { + display: flex; + align-items: center; + justify-content: space-between; + flex-shrink: 0; + padding: calc(var(--status-bar-height, 44px) + 60rpx) 24rpx 20rpx; + background: $color-bg-page; +} + +.invoice-list__back { + display: flex; + align-items: center; + justify-content: center; + width: 64rpx; + height: 64rpx; +} + +.invoice-list__back-icon { + width: 40rpx; + height: 40rpx; +} + +.invoice-list__navbar-title { + font-size: 34rpx; + font-weight: 600; + color: $color-text-primary; +} + +.invoice-list__navbar-placeholder { + width: 64rpx; + height: 64rpx; +} + +.invoice-list__scroll { + flex: 1; + height: 0; +} + +.invoice-list__content { + padding: 20rpx 24rpx calc(140rpx + env(safe-area-inset-bottom)); +} + +.invoice-list__card { + padding: 28rpx 24rpx; + margin-bottom: 20rpx; + background: $color-bg-page; + border-radius: 20rpx; + + &:last-child { + margin-bottom: 0; + } +} + +.invoice-list__card-top { + display: flex; + align-items: center; +} + +.invoice-list__card-title { + flex: 1; + min-width: 0; + font-size: 30rpx; + font-weight: 600; + color: $color-text-primary; +} + +.invoice-list__tag { + flex-shrink: 0; + margin-left: 16rpx; + padding: 4rpx 14rpx; + font-size: 22rpx; + border-radius: 6rpx; + + &--enterprise { + color: $color-primary; + border: 1rpx solid $color-primary; + } + + &--personal { + color: $color-stat-orange; + border: 1rpx solid $color-stat-orange; + } +} + +.invoice-list__tax-no { + display: block; + margin-top: 16rpx; + font-size: 24rpx; + color: #222222; + word-break: break-all; +} + +.invoice-list__card-footer { + display: flex; + align-items: center; + justify-content: space-between; + margin-top: 28rpx; +} + +.invoice-list__default { + display: flex; + align-items: center; +} + +.invoice-list__radio { + display: flex; + align-items: center; + justify-content: center; + width: 28rpx; + height: 28rpx; + border: 2rpx solid #d8dde6; + border-radius: 50%; + + &--checked { + border-color: $color-primary; + } +} + +.invoice-list__radio-dot { + width: 14rpx; + height: 14rpx; + background: $color-primary; + border-radius: 50%; +} + +.invoice-list__default-text { + margin-left: 12rpx; + font-size: 24rpx; + color: #222222; +} + +.invoice-list__actions { + display: flex; + gap: 32rpx; +} + +.invoice-list__action { + font-size: 26rpx; + color: $color-text-primary; +} + +.invoice-list__footer { + flex-shrink: 0; + padding: 16rpx 24rpx calc(16rpx + env(safe-area-inset-bottom)); + background: $color-bg-page; + border-top: 1rpx solid #f0f0f0; +} + +.invoice-list__add-btn { + display: flex; + align-items: center; + justify-content: center; + height: 88rpx; + font-size: 30rpx; + font-weight: 600; + color: #ffffff; + background: $color-primary; + border-radius: 12rpx; +} + +.invoice-list__sheet-title { + display: block; + font-size: 32rpx; + font-weight: 600; + color: $color-text-primary; +} + +.invoice-list__sheet-field { + margin-top: 32rpx; +} + +.invoice-list__sheet-label { + display: block; + margin-bottom: 16rpx; + font-size: 28rpx; + font-weight: 500; + color: $color-text-primary; +} + +.invoice-list__type-row { + display: flex; + gap: 48rpx; +} + +.invoice-list__type-option { + display: flex; + align-items: center; +} + +.invoice-list__type-radio { + display: flex; + align-items: center; + justify-content: center; + width: 32rpx; + height: 32rpx; + border: 2rpx solid #d8dde6; + border-radius: 50%; + + &--checked { + background: $color-primary; + border-color: $color-primary; + } +} + +.invoice-list__type-check { + font-size: 20rpx; + font-weight: 700; + color: #ffffff; + line-height: 1; +} + +.invoice-list__type-label { + margin-left: 12rpx; + font-size: 28rpx; + color: $color-text-primary; +} + +.invoice-list__sheet-input { + width: 100%; + height: 80rpx; + padding: 0 24rpx; + font-size: 28rpx; + color: $color-text-primary; + background: $color-bg-page; + border: 1rpx solid #e8eaef; + border-radius: 12rpx; + box-sizing: border-box; +} + +.invoice-list__sheet-placeholder { + color: $color-text-placeholder; +} + +.invoice-list__sheet-submit { + display: flex; + align-items: center; + justify-content: center; + height: 88rpx; + margin-top: 40rpx; + font-size: 30rpx; + font-weight: 600; + color: #ffffff; + background: $color-primary; + border-radius: 12rpx; +} diff --git a/src/pages/personal-center/invoice-list/index.vue b/src/pages/personal-center/invoice-list/index.vue new file mode 100644 index 0000000..91b6737 --- /dev/null +++ b/src/pages/personal-center/invoice-list/index.vue @@ -0,0 +1,290 @@ + + + + + diff --git a/src/pages/personal-center/invoice/index.scss b/src/pages/personal-center/invoice/index.scss new file mode 100644 index 0000000..28c5067 --- /dev/null +++ b/src/pages/personal-center/invoice/index.scss @@ -0,0 +1,238 @@ +@import '@/styles/variables.scss'; + +.invoice-page { + display: flex; + flex-direction: column; + min-height: 100vh; + background: $color-bg-section; +} + +.invoice-page__navbar { + display: flex; + align-items: center; + justify-content: space-between; + flex-shrink: 0; + padding: calc(var(--status-bar-height, 44px) + 60rpx) 24rpx 20rpx; + background: $color-bg-page; +} + +.invoice-page__back { + display: flex; + align-items: center; + justify-content: center; + width: 64rpx; + height: 64rpx; +} + +.invoice-page__back-icon { + width: 40rpx; + height: 40rpx; +} + +.invoice-page__navbar-title { + font-size: 34rpx; + font-weight: 600; + color: $color-text-primary; +} + +.invoice-page__navbar-placeholder { + width: 64rpx; + height: 64rpx; +} + +.invoice-page__scroll { + flex: 1; + height: 0; +} + +.invoice-page__content { + padding: 20rpx 24rpx calc(32rpx + env(safe-area-inset-bottom)); +} + +.invoice-page__section { + margin-bottom: 24rpx; +} + +.invoice-page__section-header { + display: flex; + align-items: center; + justify-content: space-between; + margin-bottom: 16rpx; +} + +.invoice-page__section-title { + font-size: 30rpx; + font-weight: 600; + color: $color-text-primary; +} + +.invoice-page__manage { + display: flex; + align-items: center; +} + +.invoice-page__manage-text { + font-size: 26rpx; + color: $color-text-secondary; +} + +.invoice-page__manage-arrow { + margin-left: 4rpx; + font-size: 26rpx; + color: $color-text-secondary; +} + +.invoice-page__header-card { + padding: 28rpx 24rpx; + background: $color-bg-page; + border-radius: 20rpx; +} + +.invoice-page__header-top { + display: flex; + align-items: center; +} + +.invoice-page__default-tag { + flex-shrink: 0; + padding: 4rpx 12rpx; + font-size: 22rpx; + color: $color-stat-orange; + background: $color-stat-orange-bg; + border-radius: 6rpx; +} + +.invoice-page__header-title { + flex: 1; + min-width: 0; + margin-left: 12rpx; + font-size: 30rpx; + font-weight: 600; + color: $color-text-primary; +} + +.invoice-page__header-type { + flex-shrink: 0; + margin-left: 16rpx; + padding: 4rpx 14rpx; + font-size: 22rpx; + border-radius: 6rpx; + + &--enterprise { + color: $color-primary; + border: 1rpx solid $color-primary; + } + + &--personal { + color: $color-stat-orange; + border: 1rpx solid $color-stat-orange; + } +} + +.invoice-page__header-tax { + display: block; + margin-top: 16rpx; + font-size: 24rpx; + color: #222222; + word-break: break-all; +} + +.invoice-page__search { + display: flex; + align-items: center; + height: 72rpx; + margin-top: 20rpx; + padding: 0 24rpx; + background: $color-bg-page; + border-radius: 36rpx; +} + +.invoice-page__search-icon { + flex-shrink: 0; + width: 32rpx; + height: 32rpx; + margin-right: 12rpx; +} + +.invoice-page__search-input { + flex: 1; + font-size: 26rpx; + color: $color-text-primary; +} + +.invoice-page__search-placeholder { + color: $color-text-placeholder; +} + +.invoice-page__tabs { + display: flex; + margin-top: 24rpx; + background: $color-bg-page; + border-radius: 20rpx; +} + +.invoice-page__tab { + position: relative; + display: flex; + flex: 1; + align-items: center; + justify-content: center; + height: 80rpx; +} + +.invoice-page__tab-text { + font-size: 28rpx; + color: $color-text-secondary; +} + +.invoice-page__tab--active .invoice-page__tab-text { + font-weight: 600; + color: $color-primary; +} + +.invoice-page__tab--active::after { + content: ''; + position: absolute; + right: 0; + bottom: 0; + left: 0; + height: 4rpx; + background: $color-primary; + border-radius: 2rpx; +} + +.invoice-page__record-card { + padding: 28rpx 24rpx; + margin-top: 20rpx; + background: $color-bg-page; + border-radius: 20rpx; +} + +.invoice-page__record-header { + display: flex; + align-items: flex-start; + justify-content: space-between; + gap: 16rpx; +} + +.invoice-page__record-title { + flex: 1; + min-width: 0; + font-size: 28rpx; + font-weight: 600; + color: $color-text-primary; +} + +.invoice-page__record-amount { + flex-shrink: 0; + font-size: 30rpx; + font-weight: 600; + color: $color-text-primary; +} + +.invoice-page__record-row { + display: block; + margin-top: 12rpx; + font-size: 24rpx; + color: $color-text-secondary; +} diff --git a/src/pages/personal-center/invoice/index.vue b/src/pages/personal-center/invoice/index.vue new file mode 100644 index 0000000..cc188e7 --- /dev/null +++ b/src/pages/personal-center/invoice/index.vue @@ -0,0 +1,175 @@ + + + + + diff --git a/src/pages/personal-center/qualification-list/index.scss b/src/pages/personal-center/qualification-list/index.scss new file mode 100644 index 0000000..8b26519 --- /dev/null +++ b/src/pages/personal-center/qualification-list/index.scss @@ -0,0 +1,131 @@ +@import '@/styles/variables.scss'; + +.qualification-list { + display: flex; + flex-direction: column; + min-height: 100vh; + background: $color-bg-section; +} + +.qualification-list__navbar { + display: flex; + align-items: center; + justify-content: space-between; + flex-shrink: 0; + padding: calc(var(--status-bar-height, 44px) + 60rpx) 24rpx 20rpx; + background: $color-bg-page; +} + +.qualification-list__back { + display: flex; + align-items: center; + justify-content: center; + width: 64rpx; + height: 64rpx; +} + +.qualification-list__back-icon { + width: 40rpx; + height: 40rpx; +} + +.qualification-list__navbar-title { + font-size: 34rpx; + font-weight: 600; + color: $color-text-primary; +} + +.qualification-list__navbar-placeholder { + width: 64rpx; + height: 64rpx; +} + +.qualification-list__scroll { + flex: 1; + height: 0; +} + +.qualification-list__content { + padding: 20rpx 24rpx calc(140rpx + env(safe-area-inset-bottom)); +} + +.qualification-list__card { + padding: 28rpx 24rpx; + margin-bottom: 20rpx; + background: $color-bg-page; + border-radius: 20rpx; + + &:last-child { + margin-bottom: 0; + } +} + +.qualification-list__card-header { + display: flex; + align-items: center; + justify-content: space-between; +} + +.qualification-list__type { + font-size: 24rpx; + color: $color-text-secondary; +} + +.qualification-list__status { + font-size: 24rpx; + color: $color-stat-orange; +} + +.qualification-list__name { + display: block; + margin-top: 12rpx; + font-size: 32rpx; + font-weight: 600; + color: $color-text-primary; +} + +.qualification-list__row { + display: block; + margin-top: 12rpx; + font-size: 24rpx; + color: #222222; + word-break: break-all; +} + +.qualification-list__actions { + display: flex; + justify-content: flex-end; + gap: 32rpx; + margin-top: 24rpx; +} + +.qualification-list__action { + font-size: 26rpx; + + &--edit { + color: $color-primary; + } + + &--delete { + color: #ef4444; + } +} + +.qualification-list__footer { + flex-shrink: 0; + padding: 16rpx 24rpx calc(16rpx + env(safe-area-inset-bottom)); + background: $color-bg-page; + border-top: 1rpx solid #f0f0f0; +} + +.qualification-list__add-btn { + display: flex; + align-items: center; + justify-content: center; + height: 88rpx; + font-size: 30rpx; + font-weight: 600; + color: #ffffff; + background: $color-primary; + border-radius: 12rpx; +} diff --git a/src/pages/personal-center/qualification-list/index.vue b/src/pages/personal-center/qualification-list/index.vue new file mode 100644 index 0000000..964ce52 --- /dev/null +++ b/src/pages/personal-center/qualification-list/index.vue @@ -0,0 +1,131 @@ + + + + + diff --git a/src/pages/personal-center/qualification-upload/index.scss b/src/pages/personal-center/qualification-upload/index.scss new file mode 100644 index 0000000..6af372a --- /dev/null +++ b/src/pages/personal-center/qualification-upload/index.scss @@ -0,0 +1,248 @@ +@import '@/styles/variables.scss'; + +.qualification-upload { + display: flex; + flex-direction: column; + min-height: 100vh; + background: $color-bg-section; +} + +.qualification-upload__navbar { + display: flex; + align-items: center; + justify-content: space-between; + flex-shrink: 0; + padding: calc(var(--status-bar-height, 44px) + 60rpx) 24rpx 20rpx; + background: $color-bg-page; +} + +.qualification-upload__back { + display: flex; + align-items: center; + justify-content: center; + width: 64rpx; + height: 64rpx; +} + +.qualification-upload__back-icon { + width: 40rpx; + height: 40rpx; +} + +.qualification-upload__navbar-title { + font-size: 34rpx; + font-weight: 600; + color: $color-text-primary; +} + +.qualification-upload__navbar-placeholder { + width: 64rpx; + height: 64rpx; +} + +.qualification-upload__scroll { + flex: 1; + height: 0; + padding: 20rpx 24rpx; + box-sizing: border-box; +} + +.qualification-upload__card { + padding: 28rpx 24rpx; + background: $color-bg-page; + border-radius: 20rpx; +} + +.qualification-upload__field { + margin-bottom: 28rpx; + + &:last-child { + margin-bottom: 0; + } +} + +.qualification-upload__label { + display: block; + margin-bottom: 16rpx; + font-size: 28rpx; + font-weight: 500; + color: $color-text-primary; +} + +.qualification-upload__required { + color: $color-text-primary; +} + +.qualification-upload__label-row { + display: flex; + align-items: center; + justify-content: space-between; + margin-bottom: 16rpx; +} + +.qualification-upload__hint { + font-size: 24rpx; + color: $color-text-secondary; +} + +.qualification-upload__input, +.qualification-upload__picker { + height: 80rpx; + padding: 0 24rpx; + background: $color-bg-page; + border: 1rpx solid #e8eaef; + border-radius: 12rpx; + box-sizing: border-box; +} + +.qualification-upload__input { + width: 100%; + font-size: 28rpx; + color: $color-text-primary; +} + +.qualification-upload__picker { + display: flex; + align-items: center; + justify-content: space-between; +} + +.qualification-upload__picker-text { + font-size: 28rpx; + color: $color-text-primary; + + &--placeholder { + color: $color-text-placeholder; + } +} + +.qualification-upload__picker-arrow { + font-size: 24rpx; + color: $color-text-secondary; +} + +.qualification-upload__placeholder { + color: $color-text-placeholder; +} + +.qualification-upload__date-row { + display: flex; + align-items: center; + gap: 16rpx; +} + +.qualification-upload__date { + display: flex; + flex: 1; + align-items: center; + justify-content: center; + height: 80rpx; + background: $color-bg-page; + border: 1rpx solid #e8eaef; + border-radius: 12rpx; +} + +.qualification-upload__date-text { + font-size: 28rpx; + color: $color-text-primary; + + &--placeholder { + color: $color-text-placeholder; + } +} + +.qualification-upload__date-sep { + flex-shrink: 0; + font-size: 28rpx; + color: $color-text-primary; +} + +.qualification-upload__attachment-row { + display: flex; + flex-wrap: wrap; + gap: 20rpx; + padding: 10rpx 10rpx 0 0; +} + +.qualification-upload__attachment-item { + position: relative; + display: flex; + flex-direction: column; + align-items: center; + width: 160rpx; + padding: 20rpx 16rpx; + background: $color-bg-section; + border-radius: 12rpx; +} + +.qualification-upload__attachment-remove { + position: absolute; + top: -10rpx; + right: -10rpx; + width: 32rpx; + height: 32rpx; +} + +.qualification-upload__attachment-remove-icon { + width: 32rpx; + height: 32rpx; +} + +.qualification-upload__attachment-icon { + width: 64rpx; + height: 64rpx; +} + +.qualification-upload__attachment-name { + margin-top: 12rpx; + font-size: 22rpx; + color: $color-text-primary; + text-align: center; + word-break: break-all; +} + +.qualification-upload__attachment-add { + display: flex; + flex-direction: column; + align-items: center; + justify-content: center; + width: 160rpx; + height: 160rpx; + background: #f8f9fb; + border: 1rpx dashed #d8dde6; + border-radius: 12rpx; +} + +.qualification-upload__attachment-add-icon { + font-size: 40rpx; + line-height: 1; + color: $color-text-secondary; +} + +.qualification-upload__attachment-add-text { + margin-top: 8rpx; + font-size: 20rpx; + color: $color-text-secondary; +} + +.qualification-upload__footer { + display: flex; + gap: 16rpx; + flex-shrink: 0; + padding: 16rpx 24rpx calc(16rpx + env(safe-area-inset-bottom)); + background: $color-bg-page; + border-top: 1rpx solid #f0f0f0; +} + +.qualification-upload__footer-btn { + display: flex; + flex: 1; + align-items: center; + justify-content: center; + height: 88rpx; + font-size: 28rpx; + font-weight: 600; + color: #ffffff; + background: $color-primary; + border-radius: 12rpx; +} diff --git a/src/pages/personal-center/qualification-upload/index.vue b/src/pages/personal-center/qualification-upload/index.vue new file mode 100644 index 0000000..05b35ce --- /dev/null +++ b/src/pages/personal-center/qualification-upload/index.vue @@ -0,0 +1,384 @@ + + + + + diff --git a/src/pages/personal-center/service-hotline/index.scss b/src/pages/personal-center/service-hotline/index.scss new file mode 100644 index 0000000..7936bd9 --- /dev/null +++ b/src/pages/personal-center/service-hotline/index.scss @@ -0,0 +1,94 @@ +@import '@/styles/variables.scss'; + +.service-hotline { + display: flex; + flex-direction: column; + min-height: 100vh; + background: $color-bg-section; +} + +.service-hotline__navbar { + display: flex; + align-items: center; + justify-content: space-between; + flex-shrink: 0; + padding: calc(var(--status-bar-height, 44px) + 60rpx) 24rpx 20rpx; + background: $color-bg-page; +} + +.service-hotline__back { + display: flex; + align-items: center; + justify-content: center; + width: 64rpx; + height: 64rpx; +} + +.service-hotline__back-icon { + width: 40rpx; + height: 40rpx; +} + +.service-hotline__navbar-title { + font-size: 34rpx; + font-weight: 600; + color: $color-text-primary; +} + +.service-hotline__navbar-placeholder { + width: 64rpx; + height: 64rpx; +} + +.service-hotline__body { + padding: 24rpx; +} + +.service-hotline__card { + display: flex; + align-items: center; + padding: 32rpx 28rpx; + background: $color-bg-page; + border-radius: 20rpx; + box-shadow: 0 8rpx 24rpx rgba(0, 0, 0, 0.04); +} + +.service-hotline__icon { + flex-shrink: 0; + width: 96rpx; + height: 96rpx; +} + +.service-hotline__info { + flex: 1; + min-width: 0; + margin-left: 24rpx; +} + +.service-hotline__title { + display: block; + font-size: 30rpx; + font-weight: 600; + color: $color-text-primary; + word-break: break-all; +} + +.service-hotline__hours { + display: block; + margin-top: 12rpx; + font-size: 24rpx; + color: $color-text-secondary; +} + +.service-hotline__dial-btn { + display: flex; + align-items: center; + justify-content: center; + height: 88rpx; + margin-top: 32rpx; + font-size: 30rpx; + font-weight: 600; + color: #ffffff; + background: $color-primary; + border-radius: 12rpx; +} diff --git a/src/pages/personal-center/service-hotline/index.vue b/src/pages/personal-center/service-hotline/index.vue new file mode 100644 index 0000000..8a24936 --- /dev/null +++ b/src/pages/personal-center/service-hotline/index.vue @@ -0,0 +1,75 @@ + + + + + diff --git a/src/static/icon/service-hotline.svg b/src/static/icon/service-hotline.svg new file mode 100644 index 0000000..2042334 --- /dev/null +++ b/src/static/icon/service-hotline.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/src/types/address.ts b/src/types/address.ts new file mode 100644 index 0000000..9b9806c --- /dev/null +++ b/src/types/address.ts @@ -0,0 +1,8 @@ +export interface AddressItem { + id: string + name: string + phone: string + region: string + detail: string + isDefault: boolean +} diff --git a/src/types/contract.ts b/src/types/contract.ts new file mode 100644 index 0000000..e80f807 --- /dev/null +++ b/src/types/contract.ts @@ -0,0 +1,23 @@ +export type ContractTab = 'all' | 'pending' | 'signed' + +export type ContractSignStatus = 'signed' | 'pending' + +export type ContractBadgeType = 'signed' | 'in_progress' | 'pending_sign' + +export interface ContractBadge { + type: ContractBadgeType + label: string +} + +export interface ContractItem { + id: string + contractNo: string + title: string + type: string + relatedLabel: string + relatedValue: string + signStatus: ContractSignStatus + badges: ContractBadge[] + showDownload: boolean + showSign: boolean +} diff --git a/src/types/invoice-list.ts b/src/types/invoice-list.ts new file mode 100644 index 0000000..fae36cb --- /dev/null +++ b/src/types/invoice-list.ts @@ -0,0 +1,9 @@ +export type InvoiceHeaderType = 'enterprise' | 'personal' + +export interface InvoiceHeaderItem { + id: string + title: string + type: InvoiceHeaderType + taxNo: string + isDefault: boolean +} diff --git a/src/types/invoice.ts b/src/types/invoice.ts new file mode 100644 index 0000000..40b4eee --- /dev/null +++ b/src/types/invoice.ts @@ -0,0 +1,14 @@ +export type InvoiceRecordStatus = 'all' | 'invoiced' | 'not_invoiced' | 'invoicing' + +export type InvoiceRecordItemStatus = Exclude + +export interface InvoiceRecordItem { + id: string + title: string + ratio: string + amount: number + transactionNo: string + relatedProject: string + invoiceTime: string + status: InvoiceRecordItemStatus +} diff --git a/src/types/qualification.ts b/src/types/qualification.ts new file mode 100644 index 0000000..b871fba --- /dev/null +++ b/src/types/qualification.ts @@ -0,0 +1,12 @@ +export type QualificationStatus = 'reviewing' | 'approved' | 'rejected' | 'draft' + +export interface QualificationItem { + id: string + type: string + certificateName: string + certificateNo: string + issuer: string + validFrom: string + validTo: string + status: QualificationStatus +} diff --git a/src/utils/quick-entry-navigate.ts b/src/utils/quick-entry-navigate.ts new file mode 100644 index 0000000..abe0b76 --- /dev/null +++ b/src/utils/quick-entry-navigate.ts @@ -0,0 +1,39 @@ +const TAB_BAR_PATHS = new Set([ + '/pages/home-index/index', + '/pages/case-library/index', + '/pages/message-center/index', + '/pages/project-center/index', + '/pages/personal-center/index', +]) + +const QUICK_ENTRY_ROUTES: Record = { + project: '/pages/project-center/index', + report: '/pages/home-index/requirement-submit/index', + service: '/pages/message-center/customer-service/index', + contract: '/pages/contract-center/index', + finance: '/pages/personal-center/finance/index', + personal: '/pages/personal-center/index', + message: '/pages/message-center/index', + security: '/pages/personal-center/account-security/index', + feedback: '/pages/personal-center/feedback/index', + 'contract-list': '/pages/contract-center/index', + invoice: '/pages/personal-center/invoice/index', + address: '/pages/personal-center/address/index', + favorites: '/pages/case-library/favorites/index', + qualification: '/pages/personal-center/qualification-list/index', +} + +export function navigateQuickEntry(id: string, label: string) { + const path = QUICK_ENTRY_ROUTES[id] + if (!path) { + uni.showToast({ title: `${label}开发中`, icon: 'none' }) + return + } + + if (TAB_BAR_PATHS.has(path)) { + uni.redirectTo({ url: path }) + return + } + + uni.navigateTo({ url: path }) +}