diff --git a/scripts/extract-vue-styles.mjs b/scripts/extract-vue-styles.mjs new file mode 100644 index 0000000..a4799c2 --- /dev/null +++ b/scripts/extract-vue-styles.mjs @@ -0,0 +1,68 @@ +import fs from 'node:fs' +import path from 'node:path' +import { fileURLToPath } from 'node:url' + +const root = path.join(path.dirname(fileURLToPath(import.meta.url)), '..', 'src') + +function walk(dir, files = []) { + for (const name of fs.readdirSync(dir)) { + const full = path.join(dir, name) + if (fs.statSync(full).isDirectory()) + walk(full, files) + else if (name.endsWith('.vue')) + files.push(full) + } + return files +} + +function extractVue(vuePath) { + const content = fs.readFileSync(vuePath, 'utf8') + const base = path.basename(vuePath, '.vue') + const dir = path.dirname(vuePath) + const scssPath = path.join(dir, `${base}.scss`) + + const patterns = [ + { + regex: /`, + }, + { + regex: /`, + }, + { + regex: /`, + }, + { + regex: /`, + }, + ] + + for (const { regex, replacement } of patterns) { + const match = content.match(regex) + if (!match) + continue + + const styleBody = match[1].trimEnd() + if (styleBody.includes(`@import './${base}.scss'`)) + return false + + fs.writeFileSync(scssPath, `${styleBody}\n`, 'utf8') + const next = content.replace(regex, replacement()) + fs.writeFileSync(vuePath, next, 'utf8') + return true + } + + return false +} + +const vueFiles = walk(root) +let count = 0 +for (const file of vueFiles) { + if (extractVue(file)) + count += 1 +} + +console.log(`Extracted styles from ${count} Vue files.`) diff --git a/src/App.scss b/src/App.scss new file mode 100644 index 0000000..8958c3c --- /dev/null +++ b/src/App.scss @@ -0,0 +1,6 @@ +@import '@/styles/fonts.scss'; + +page { + font-family: -apple-system, BlinkMacSystemFont, 'PingFang SC', 'Helvetica Neue', sans-serif; + background-color: #ffffff; +} diff --git a/src/App.vue b/src/App.vue index dc0a09c..600ba39 100644 --- a/src/App.vue +++ b/src/App.vue @@ -5,10 +5,5 @@ onLaunch(() => {}) diff --git a/src/components/AppFooter.scss b/src/components/AppFooter.scss new file mode 100644 index 0000000..e8326a3 --- /dev/null +++ b/src/components/AppFooter.scss @@ -0,0 +1,12 @@ +.footer{ + position: absolute; + bottom: 1rem; + left: 50%; + transform: translateX(-50%); + color: #888; +} +.uni-helper-github__image { + display: inline-block; + height: 1em; + width: 1em; +} diff --git a/src/components/AppFooter.vue b/src/components/AppFooter.vue index 61049b6..469d7f8 100644 --- a/src/components/AppFooter.vue +++ b/src/components/AppFooter.vue @@ -18,17 +18,6 @@ function handleClickGithub() { - diff --git a/src/components/AppLogos.scss b/src/components/AppLogos.scss new file mode 100644 index 0000000..3703b1f --- /dev/null +++ b/src/components/AppLogos.scss @@ -0,0 +1,34 @@ +.container { + display: inline-flex; + font-size: 1.5rem; + font-weight: 300; + &:hover { + .link-bar { + transform: rotate(135deg); + } + } +} +.uni-helper-logo { + display: flex; + flex-direction: column; + align-items: center; + .uni-helper-logo__image { + display: inline-block; + height: 4.5rem; + width: 4.5rem; + } + .uni-helper-logo__label { + margin-top: -0.5rem; + } + .green { + color: #22c55e; + }; + .purple { + color: #a855f7; + } +} +.link-bar { + color: #9ca3af; + margin: auto 1em; + transition: all 500ms cubic-bezier(0.4, 0, 0.2, 1); +} diff --git a/src/components/AppLogos.vue b/src/components/AppLogos.vue index 8779ca6..4acd6bf 100644 --- a/src/components/AppLogos.vue +++ b/src/components/AppLogos.vue @@ -22,38 +22,5 @@ diff --git a/src/components/AppTabBar.scss b/src/components/AppTabBar.scss new file mode 100644 index 0000000..4b9fc41 --- /dev/null +++ b/src/components/AppTabBar.scss @@ -0,0 +1,38 @@ +@import '@/styles/variables.scss'; + +.app-tab-bar { + position: fixed; + right: 0; + bottom: 0; + left: 0; + z-index: 100; + display: flex; + align-items: center; + justify-content: space-around; + padding: 12rpx 0 calc(12rpx + env(safe-area-inset-bottom)); + background: $color-bg-page; + border-top: 1rpx solid #f0f0f0; +} + +.app-tab-bar__item { + display: flex; + flex: 1; + flex-direction: column; + align-items: center; +} + +.app-tab-bar__icon { + width: 44rpx; + height: 44rpx; +} + +.app-tab-bar__label { + margin-top: 6rpx; + font-size: 20rpx; + color: $color-text-secondary; + + &--active { + color: $color-primary; + font-weight: 500; + } +} diff --git a/src/components/AppTabBar.vue b/src/components/AppTabBar.vue index d8b16ad..4349286 100644 --- a/src/components/AppTabBar.vue +++ b/src/components/AppTabBar.vue @@ -48,42 +48,5 @@ function handleSwitch(path: string, key: TabKey) { diff --git a/src/components/InputEntry.scss b/src/components/InputEntry.scss new file mode 100644 index 0000000..484dba8 --- /dev/null +++ b/src/components/InputEntry.scss @@ -0,0 +1,16 @@ +.input-box { + margin: 1rem; + padding: 0.5rem; + border-bottom: 1px solid gray; +} +.popup { + position: fixed; + top: 2rem; + left: 0px; + right: 0px; + .popup_label { + padding: 0.5rem 2rem; + background: gray; + border-radius: 8px; + } +} diff --git a/src/components/InputEntry.vue b/src/components/InputEntry.vue index b63a59a..92a40a0 100644 --- a/src/components/InputEntry.vue +++ b/src/components/InputEntry.vue @@ -33,20 +33,5 @@ function handleClick() { diff --git a/src/constants/bill-list.ts b/src/constants/bill-list.ts new file mode 100644 index 0000000..9ba6ac9 --- /dev/null +++ b/src/constants/bill-list.ts @@ -0,0 +1,49 @@ +import { PROJECT_CENTER_LIST } from '@/constants/project-center' +import { getProjectDetail } from '@/constants/project-detail' +import type { BillItem, BillListSummary } from '@/types/bill' + +const PAID_BILL_META: Record = { + '1-1': { + paidAt: '2026-01-21 15:00:00', + paidMethod: 'wechat', + transactionNo: 'T20260819153035678K2M001', + }, +} + +function buildBillList(): BillItem[] { + const bills: BillItem[] = [] + + PROJECT_CENTER_LIST.forEach((project) => { + const detail = getProjectDetail(project.id) + if (!detail) + return + + detail.paymentPlans.forEach((plan) => { + const metaKey = `${project.id}-${plan.id}` + const paidMeta = PAID_BILL_META[metaKey] + + bills.push({ + ...plan, + projectId: project.id, + billNo: plan.id === '1' && project.id === '1' ? '20260813ZZ251245' : plan.billNo, + transactionNo: paidMeta?.transactionNo || plan.transactionNo, + paidAt: paidMeta?.paidAt, + paidMethod: paidMeta?.paidMethod, + }) + }) + }) + + return bills +} + +export const BILL_LIST: BillItem[] = buildBillList() + +export const BILL_LIST_SUMMARY: BillListSummary = { + totalCount: 10, + totalAmount: '40.0万', + pendingCount: 3, +} + +export function getBill(projectId: string, planId: string): BillItem | null { + return BILL_LIST.find(bill => bill.projectId === projectId && bill.id === planId) || null +} diff --git a/src/constants/personal-center.ts b/src/constants/personal-center.ts new file mode 100644 index 0000000..2f6b2ef --- /dev/null +++ b/src/constants/personal-center.ts @@ -0,0 +1,37 @@ +import type { PersonalCenterMenuItem, PersonalCenterProfile } from '@/types/personal-center' +import avatarIcon from '@/static/icon/avatar.png' +import iconAbout from '@/static/icon/about.png' +import iconAddress from '@/static/icon/address.png' +import iconContractList from '@/static/icon/contract-list.png' +import iconFavorites from '@/static/icon/favorites.png' +import iconFeedback from '@/static/icon/feedback.png' +import iconFinance from '@/static/icon/finance.png' +import iconHelp from '@/static/icon/help.png' +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' + +export const PERSONAL_CENTER_PROFILE: PersonalCenterProfile = { + nickname: '这里是昵称', + phone: '13589898989', + avatar: avatarIcon, +} + +export const PERSONAL_CENTER_MENU: PersonalCenterMenuItem[] = [ + { key: 'security', label: '账号安全', icon: iconSecurity }, + { key: 'message-push', label: '消息推送', icon: iconMessagePush }, + { key: 'feedback', label: '意见反馈', icon: iconFeedback }, + { key: 'contract-list', label: '合同列表', icon: iconContractList }, + { key: 'finance', label: '财务管理', icon: iconFinance, path: '/pages/project-center/bill-list/index' }, + { key: 'invoice', label: '发票列表', icon: iconInvoice }, + { key: 'address', label: '地址管理', icon: iconAddress }, + { key: 'favorites', label: '收藏列表', icon: iconFavorites, path: '/pages/case-library/favorites/index' }, + { key: 'qualification', label: '资质列表', icon: iconQualification }, + { key: 'help', label: '帮助中心', icon: iconHelp }, + { key: 'about', label: '关于我们', icon: iconAbout }, + { key: 'service-hotline', label: '专属客服热线', icon: iconServiceHotline }, +] + +export const PERSONAL_CENTER_SERVICE_HOTLINE = '400-000-0000' diff --git a/src/constants/project-detail.ts b/src/constants/project-detail.ts index 6341e98..0d1dea0 100644 --- a/src/constants/project-detail.ts +++ b/src/constants/project-detail.ts @@ -47,6 +47,48 @@ const DEFAULT_FILES = [ { id: '3', name: '参考图.png', icon: '/static/icons/PNG.png' }, ] +const DEFAULT_PAYMENT_PLANS = [ + { + id: '1', + title: '第一期·预付款', + ratio: '比例33%', + status: 'paid' as const, + transactionNo: '202608131104121251', + billNo: '202608131104121251', + relatedProject: '社区康养智慧系统', + amount: 20100, + }, + { + id: '2', + title: '第二期·进度款', + ratio: '比例33%', + status: 'pending' as const, + transactionNo: '202608131104121252', + billNo: '202608131104121252', + relatedProject: '社区康养智慧系统', + amount: 20100, + }, + { + id: '3', + title: '第三期·尾款', + ratio: '比例34%', + status: 'not_due' as const, + transactionNo: '202608131104121253', + billNo: '202608131104121253', + relatedProject: '社区康养智慧系统', + amount: 20100, + }, +] + +const DEFAULT_AFTER_SALES = { + processing: true, + bannerTitle: '售后工单处理中', + bannerDesc: '工程师正在处理您的修改需求,请耐心等待', + type: 'bug问题', + description: '具体请看清单', + attachments: DEFAULT_FILES.map(file => ({ ...file, id: `as-${file.id}` })), +} + function buildDetail(item: typeof PROJECT_CENTER_LIST[number]): ProjectDetail { const progress = item.progress ?? 0 @@ -57,8 +99,19 @@ function buildDetail(item: typeof PROJECT_CENTER_LIST[number]): ProjectDetail { steps: DEFAULT_STEPS.map(step => ({ ...step })), team: DEFAULT_TEAM.map(member => ({ ...member })), files: DEFAULT_FILES.map(file => ({ ...file })), - financeSummary: '合同金额已确认,当前处于开发阶段付款节点,发票与回款记录可在后台查看。', - afterSalesSummary: '项目交付后将提供一年免费运维服务,支持 7×24 小时远程技术支持与故障响应。', + paymentPlans: DEFAULT_PAYMENT_PLANS.map(plan => ({ ...plan })), + paymentPlanFiles: DEFAULT_FILES.map((file, index) => ({ + ...file, + id: `pay-${index + 1}`, + })), + contractFiles: DEFAULT_FILES.map((file, index) => ({ + ...file, + id: `contract-${index + 1}`, + })), + afterSales: { + ...DEFAULT_AFTER_SALES, + attachments: DEFAULT_AFTER_SALES.attachments.map(file => ({ ...file })), + }, progress, } } @@ -70,3 +123,17 @@ const PROJECT_DETAIL_MAP: Record = Object.fromEntries( export function getProjectDetail(id: string): ProjectDetail | null { return PROJECT_DETAIL_MAP[id] || null } + +export function getPaymentPlan(projectId: string, planId: string) { + const detail = getProjectDetail(projectId) + if (!detail) + return null + + return detail.paymentPlans.find(plan => plan.id === planId) || null +} + +export const PAYMENT_PLAN_STATUS_LABEL: Record = { + paid: '已支付', + pending: '待支付', + not_due: '未到期', +} diff --git a/src/pages.json b/src/pages.json index 3772666..0aae421 100644 --- a/src/pages.json +++ b/src/pages.json @@ -115,6 +115,36 @@ "navigationStyle": "custom" } }, + { + "path": "pages/project-center/payment/index", + "style": { + "navigationStyle": "custom" + } + }, + { + "path": "pages/project-center/payment-success/index", + "style": { + "navigationStyle": "custom" + } + }, + { + "path": "pages/project-center/bill-list/index", + "style": { + "navigationStyle": "custom" + } + }, + { + "path": "pages/project-center/bill-detail/index", + "style": { + "navigationStyle": "custom" + } + }, + { + "path": "pages/project-center/after-sales-apply/index", + "style": { + "navigationStyle": "custom" + } + }, { "path": "pages/personal-center/index", "style": { diff --git a/src/pages/Login/splash/index.scss b/src/pages/Login/splash/index.scss new file mode 100644 index 0000000..1772f78 --- /dev/null +++ b/src/pages/Login/splash/index.scss @@ -0,0 +1,53 @@ +@import '@/styles/variables.scss'; + +.splash { + position: relative; + width: 100vw; + height: 100vh; + overflow: hidden; + background: linear-gradient(180deg, $color-splash-gradient-start 0%, $color-splash-gradient-end 100%); +} + +.splash__bg-circle { + position: absolute; + top: 50%; + right: -120rpx; + width: 520rpx; + height: 520rpx; + border-radius: 50%; + background: $color-splash-circle; + transform: translateY(-50%); +} + +.splash__content { + position: relative; + z-index: 1; + display: flex; + flex-direction: column; + align-items: center; + padding-top: 38vh; +} + +.splash__logo { + width: 160rpx; + height: 160rpx; +} + +.splash__title { + margin-top: 40rpx; + font-family: 'Alimama FangYuanTi VF-Bold', 'Alimama FangYuanTi VF', sans-serif; + font-size: 61.07rpx; + font-weight: 700; + font-variation-settings: 'wght' 700, 'BEVL' 100; + color: $color-text-primary; + letter-spacing: 2rpx; +} + +.splash__subtitle { + margin-top: 16rpx; + font-family: 'PingFangSC-Regular', 'PingFang SC', sans-serif; + font-size: 22.9rpx; + font-weight: 400; + color: $color-text-secondary; + letter-spacing: 1rpx; +} diff --git a/src/pages/Login/splash/index.vue b/src/pages/Login/splash/index.vue index 348ca75..2d493eb 100644 --- a/src/pages/Login/splash/index.vue +++ b/src/pages/Login/splash/index.vue @@ -33,57 +33,5 @@ onMounted(() => { diff --git a/src/pages/Login/user-agreement/index.scss b/src/pages/Login/user-agreement/index.scss new file mode 100644 index 0000000..01db819 --- /dev/null +++ b/src/pages/Login/user-agreement/index.scss @@ -0,0 +1,86 @@ +@import '@/styles/variables.scss'; + +.user-agreement-page { + display: flex; + flex-direction: column; + height: 100vh; + background: $color-bg-page; +} + +.user-agreement-page__navbar { + display: flex; + align-items: center; + justify-content: space-between; + padding: calc(env(safe-area-inset-top) + 20rpx) 32rpx 20rpx; + background: $color-bg-page; + border-bottom: 1rpx solid #f0f0f0; +} + +.user-agreement-page__back { + display: flex; + align-items: center; + justify-content: center; + width: 64rpx; + height: 64rpx; +} + +.user-agreement-page__back-icon { + width: 40rpx; + height: 40rpx; +} + +.user-agreement-page__navbar-title { + font-size: 34rpx; + font-weight: 600; + color: $color-text-primary; +} + +.user-agreement-page__navbar-placeholder { + width: 64rpx; + height: 64rpx; +} + +.user-agreement-page__scroll { + flex: 1; + height: 0; +} + +.user-agreement-page__content { + padding: 32rpx 40rpx calc(40rpx + env(safe-area-inset-bottom)); +} + +.user-agreement-page__doc-title { + display: block; + margin-bottom: 24rpx; + font-size: 36rpx; + font-weight: 700; + line-height: 1.5; + color: $color-text-primary; +} + +.user-agreement-page__date { + display: block; + margin-bottom: 8rpx; + font-size: 28rpx; + line-height: 1.6; + color: $color-text-primary; +} + +.user-agreement-page__section-title { + display: block; + margin-top: 40rpx; + margin-bottom: 16rpx; + font-size: 30rpx; + font-weight: 600; + line-height: 1.5; + color: $color-text-primary; +} + +.user-agreement-page__paragraph { + display: block; + margin-bottom: 16rpx; + font-size: 28rpx; + line-height: 1.8; + color: $color-text-primary; + text-align: justify; +} diff --git a/src/pages/Login/user-agreement/index.vue b/src/pages/Login/user-agreement/index.vue index d07c69d..92cd5ab 100644 --- a/src/pages/Login/user-agreement/index.vue +++ b/src/pages/Login/user-agreement/index.vue @@ -70,90 +70,5 @@ function handleBack() { diff --git a/src/pages/Login/user-forgot-password/components/CodeInput.scss b/src/pages/Login/user-forgot-password/components/CodeInput.scss new file mode 100644 index 0000000..dd27f8f --- /dev/null +++ b/src/pages/Login/user-forgot-password/components/CodeInput.scss @@ -0,0 +1,47 @@ +@import '@/styles/variables.scss'; + +.code-input { + display: flex; + align-items: center; + width: 100%; + height: 96rpx; + padding: 0 16rpx 0 32rpx; + box-sizing: border-box; + background: $color-bg-input; + border-radius: 48rpx; +} + +.code-input__field { + flex: 1; + height: 96rpx; + font-size: 30rpx; + color: $color-text-primary; + background: transparent; +} + +.code-input__placeholder { + font-size: 30rpx; + color: $color-text-placeholder; +} + +.code-input__btn { + display: flex; + flex-shrink: 0; + align-items: center; + justify-content: center; + height: 64rpx; + padding: 0 24rpx; + background: $color-primary; + border-radius: 32rpx; + + &--disabled { + opacity: 0.6; + } +} + +.code-input__btn-text { + font-size: 24rpx; + font-weight: 500; + color: #ffffff; + white-space: nowrap; +} diff --git a/src/pages/Login/user-forgot-password/components/CodeInput.vue b/src/pages/Login/user-forgot-password/components/CodeInput.vue index 3ddc55e..a45f64c 100644 --- a/src/pages/Login/user-forgot-password/components/CodeInput.vue +++ b/src/pages/Login/user-forgot-password/components/CodeInput.vue @@ -61,51 +61,5 @@ function handleGetCode() { diff --git a/src/pages/Login/user-forgot-password/components/ForgotInput.scss b/src/pages/Login/user-forgot-password/components/ForgotInput.scss new file mode 100644 index 0000000..b16322c --- /dev/null +++ b/src/pages/Login/user-forgot-password/components/ForgotInput.scss @@ -0,0 +1,25 @@ +@import '@/styles/variables.scss'; + +.forgot-input { + display: flex; + align-items: center; + width: 100%; + height: 96rpx; + padding: 0 32rpx; + box-sizing: border-box; + background: $color-bg-input; + border-radius: 48rpx; +} + +.forgot-input__field { + flex: 1; + height: 96rpx; + font-size: 30rpx; + color: $color-text-primary; + background: transparent; +} + +.forgot-input__placeholder { + font-size: 30rpx; + color: $color-text-placeholder; +} diff --git a/src/pages/Login/user-forgot-password/components/ForgotInput.vue b/src/pages/Login/user-forgot-password/components/ForgotInput.vue index 755527e..3087ee8 100644 --- a/src/pages/Login/user-forgot-password/components/ForgotInput.vue +++ b/src/pages/Login/user-forgot-password/components/ForgotInput.vue @@ -34,29 +34,5 @@ function onInput(e: { detail: { value: string } }) { diff --git a/src/pages/Login/user-forgot-password/components/PasswordField.scss b/src/pages/Login/user-forgot-password/components/PasswordField.scss new file mode 100644 index 0000000..f946fab --- /dev/null +++ b/src/pages/Login/user-forgot-password/components/PasswordField.scss @@ -0,0 +1,32 @@ +@import '@/styles/variables.scss'; + +.password-field { + display: flex; + align-items: center; + width: 100%; + height: 96rpx; + padding: 0 32rpx; + box-sizing: border-box; + background: $color-bg-input; + border-radius: 48rpx; +} + +.password-field__field { + flex: 1; + height: 96rpx; + font-size: 30rpx; + color: $color-text-primary; + background: transparent; +} + +.password-field__placeholder { + font-size: 30rpx; + color: $color-text-placeholder; +} + +.password-field__eye { + flex-shrink: 0; + width: 40rpx; + height: 40rpx; + margin-left: 16rpx; +} diff --git a/src/pages/Login/user-forgot-password/components/PasswordField.vue b/src/pages/Login/user-forgot-password/components/PasswordField.vue index efb43e6..ba12cce 100644 --- a/src/pages/Login/user-forgot-password/components/PasswordField.vue +++ b/src/pages/Login/user-forgot-password/components/PasswordField.vue @@ -47,36 +47,5 @@ function toggleVisible() { diff --git a/src/pages/Login/user-forgot-password/index.scss b/src/pages/Login/user-forgot-password/index.scss new file mode 100644 index 0000000..e55f9f0 --- /dev/null +++ b/src/pages/Login/user-forgot-password/index.scss @@ -0,0 +1,127 @@ +@import '@/styles/variables.scss'; + +.forgot-page { + display: flex; + flex-direction: column; + min-height: 100vh; + padding: 0 64rpx; + background: $color-bg-page; +} + +.forgot-page__header { + padding-top: 120rpx; + text-align: center; +} + +.forgot-page__title { + display: block; + font-size: 56rpx; + font-weight: 700; + color: $color-text-primary; + letter-spacing: 2rpx; +} + +.forgot-page__subtitle { + display: block; + margin-top: 16rpx; + font-size: 28rpx; + font-weight: 400; + color: $color-text-secondary; +} + +.forgot-page__form { + width: 100%; + margin-top: 80rpx; + box-sizing: border-box; +} + +.forgot-page__field { + width: 100%; + margin-top: 24rpx; + box-sizing: border-box; +} + +.forgot-page__agreement { + display: flex; + align-items: flex-start; + margin-top: 32rpx; +} + +.forgot-page__checkbox { + display: flex; + flex-shrink: 0; + align-items: center; + justify-content: center; + width: 32rpx; + height: 32rpx; + margin-top: 4rpx; + margin-right: 12rpx; + border: 2rpx solid #cccccc; + border-radius: 50%; + transition: all 0.2s; + + &--checked { + background: $color-primary; + border-color: $color-primary; + } +} + +.forgot-page__checkmark { + font-size: 20rpx; + font-weight: 700; + color: #ffffff; + line-height: 1; +} + +.forgot-page__agreement-text { + flex: 1; + font-size: 24rpx; + line-height: 1.6; +} + +.forgot-page__agreement-normal { + color: $color-text-secondary; +} + +.forgot-page__agreement-link { + color: $color-text-link; +} + +.forgot-page__submit { + display: flex; + align-items: center; + justify-content: center; + width: 100%; + height: 96rpx; + margin-top: 48rpx; + font-size: 32rpx; + font-weight: 600; + color: #ffffff; + background: $color-primary; + border: none; + border-radius: 48rpx; + line-height: 96rpx; + + &::after { + border: none; + } +} + +.forgot-page__footer { + display: flex; + align-items: center; + justify-content: center; + margin-top: auto; + padding: 60rpx 0 calc(60rpx + env(safe-area-inset-bottom)); +} + +.forgot-page__footer-normal { + font-size: 28rpx; + color: $color-text-secondary; +} + +.forgot-page__footer-link { + margin-left: 4rpx; + font-size: 28rpx; + color: $color-text-link; +} diff --git a/src/pages/Login/user-forgot-password/index.vue b/src/pages/Login/user-forgot-password/index.vue index 2b3eeb8..73c13ae 100644 --- a/src/pages/Login/user-forgot-password/index.vue +++ b/src/pages/Login/user-forgot-password/index.vue @@ -143,131 +143,5 @@ function handleUserAgreement() { diff --git a/src/pages/Login/user-login/components/LoginInput.scss b/src/pages/Login/user-login/components/LoginInput.scss new file mode 100644 index 0000000..f954a4c --- /dev/null +++ b/src/pages/Login/user-login/components/LoginInput.scss @@ -0,0 +1,32 @@ +@import '@/styles/variables.scss'; + +.login-input { + display: flex; + align-items: center; + width: 100%; + height: 96rpx; + padding: 0 32rpx; + box-sizing: border-box; + background: $color-bg-input; + border-radius: 48rpx; +} + +.login-input__icon { + flex-shrink: 0; + width: 40rpx; + height: 40rpx; + margin-right: 20rpx; +} + +.login-input__field { + flex: 1; + height: 96rpx; + font-size: 30rpx; + color: $color-text-primary; + background: transparent; +} + +.login-input__placeholder { + font-size: 30rpx; + color: $color-text-placeholder; +} diff --git a/src/pages/Login/user-login/components/LoginInput.vue b/src/pages/Login/user-login/components/LoginInput.vue index c4f8574..f0554ce 100644 --- a/src/pages/Login/user-login/components/LoginInput.vue +++ b/src/pages/Login/user-login/components/LoginInput.vue @@ -42,36 +42,5 @@ function onInput(e: { detail: { value: string } }) { diff --git a/src/pages/Login/user-login/index.scss b/src/pages/Login/user-login/index.scss new file mode 100644 index 0000000..6409e9d --- /dev/null +++ b/src/pages/Login/user-login/index.scss @@ -0,0 +1,188 @@ +@import '@/styles/variables.scss'; + +.login-page { + display: flex; + flex-direction: column; + min-height: 100vh; + padding: 0 64rpx; + background: $color-bg-page; +} + +.login-page__header { + padding-top: 120rpx; + text-align: center; +} + +.login-page__title { + display: block; + font-size: 56rpx; + font-weight: 700; + color: $color-text-primary; + letter-spacing: 2rpx; +} + +.login-page__subtitle { + display: block; + margin-top: 16rpx; + font-size: 28rpx; + font-weight: 400; + color: $color-text-secondary; +} + +.login-page__form { + width: 100%; + margin-top: 80rpx; + box-sizing: border-box; +} + +.login-page__password-group { + margin-top: 24rpx; +} + +.login-page__forgot { + display: block; + margin-top: 16rpx; + font-size: 26rpx; + color: $color-text-secondary; +} + +.login-page__agreement { + display: flex; + align-items: flex-start; + margin-top: 32rpx; +} + +.login-page__checkbox { + display: flex; + flex-shrink: 0; + align-items: center; + justify-content: center; + width: 32rpx; + height: 32rpx; + margin-top: 4rpx; + margin-right: 12rpx; + border: 2rpx solid #cccccc; + border-radius: 50%; + transition: all 0.2s; + + &--checked { + background: $color-primary; + border-color: $color-primary; + } +} + +.login-page__checkmark { + font-size: 20rpx; + font-weight: 700; + color: #ffffff; + line-height: 1; +} + +.login-page__agreement-text { + flex: 1; + font-size: 24rpx; + line-height: 1.6; +} + +.login-page__agreement-normal { + color: $color-text-secondary; +} + +.login-page__agreement-link { + color: $color-text-link; +} + +.login-page__submit { + display: flex; + align-items: center; + justify-content: center; + width: 100%; + height: 96rpx; + margin-top: 48rpx; + font-size: 32rpx; + font-weight: 600; + color: #ffffff; + background: $color-primary; + border: none; + border-radius: 48rpx; + line-height: 96rpx; + + &::after { + border: none; + } +} + +.login-page__other { + flex: 1; + display: flex; + flex-direction: column; + align-items: center; + justify-content: center; + padding: 60rpx 0; +} + +.login-page__divider { + display: flex; + align-items: center; + width: 100%; +} + +.login-page__divider-line { + flex: 1; + height: 1rpx; + background: #e8e8e8; +} + +.login-page__divider-text { + padding: 0 24rpx; + font-size: 24rpx; + color: $color-text-secondary; + white-space: nowrap; +} + +.login-page__sms { + display: flex; + flex-direction: column; + align-items: center; + width: fit-content; + margin-top: 48rpx; +} + +.login-page__sms-icon-wrap { + display: flex; + align-items: center; + justify-content: center; + width: 96rpx; + height: 96rpx; + background: #B6CDFF; + border-radius: 50%; +} + +.login-page__sms-icon { + width: 48rpx; + height: 48rpx; +} + +.login-page__sms-text { + margin-top: 16rpx; + font-size: 24rpx; + color: #999999; +} + +.login-page__footer { + display: flex; + align-items: center; + justify-content: center; + padding-bottom: calc(60rpx + env(safe-area-inset-bottom)); +} + +.login-page__footer-normal { + font-size: 28rpx; + color: $color-text-secondary; +} + +.login-page__footer-link { + margin-left: 4rpx; + font-size: 28rpx; + color: $color-text-link; +} diff --git a/src/pages/Login/user-login/index.vue b/src/pages/Login/user-login/index.vue index 77161fc..d3e4215 100644 --- a/src/pages/Login/user-login/index.vue +++ b/src/pages/Login/user-login/index.vue @@ -172,192 +172,5 @@ function handleUserAgreement() { diff --git a/src/pages/Login/user-register-success/index.scss b/src/pages/Login/user-register-success/index.scss new file mode 100644 index 0000000..664e8bd --- /dev/null +++ b/src/pages/Login/user-register-success/index.scss @@ -0,0 +1,36 @@ +@import '@/styles/variables.scss'; + +.result-page { + display: flex; + align-items: center; + justify-content: center; + min-height: 100vh; + background: $color-bg-page; +} + +.result-page__content { + display: flex; + flex-direction: column; + align-items: center; + padding: 0 64rpx; +} + +.result-page__icon { + width: 160rpx; + height: 160rpx; +} + +.result-page__title { + margin-top: 48rpx; + font-size: 40rpx; + font-weight: 700; + color: $color-text-primary; + letter-spacing: 1rpx; +} + +.result-page__subtitle { + margin-top: 24rpx; + font-size: 28rpx; + font-weight: 400; + color: $color-text-secondary; +} diff --git a/src/pages/Login/user-register-success/index.vue b/src/pages/Login/user-register-success/index.vue index dd8c19f..aa799d8 100644 --- a/src/pages/Login/user-register-success/index.vue +++ b/src/pages/Login/user-register-success/index.vue @@ -8,11 +8,19 @@ import { } from '@/types/result-page' const pageType = ref('register') +const projectId = ref('') const countdown = ref(RESULT_REDIRECT_DELAY / 1000) let timer: ReturnType | null = null const pageConfig = computed(() => RESULT_PAGE_CONFIG[pageType.value]) +const redirectUrl = computed(() => { + if (pageType.value === 'afterSalesSuccess' && projectId.value) { + return `${pageConfig.value.redirectUrl}?id=${encodeURIComponent(projectId.value)}&tab=aftersales` + } + return pageConfig.value.redirectUrl +}) + const title = computed(() => pageConfig.value.title) const subtitle = computed(() => `${countdown.value}秒后自动跳转至${pageConfig.value.subtitleTarget}`) @@ -29,6 +37,13 @@ onLoad((options) => { } if (type === 'submitSuccess') { pageType.value = 'submitSuccess' + return + } + if (type === 'afterSalesSuccess') { + pageType.value = 'afterSalesSuccess' + const id = options?.id + if (id) + projectId.value = decodeURIComponent(String(id)) } }) @@ -41,7 +56,7 @@ onMounted(() => { timer = null } uni.redirectTo({ - url: pageConfig.value.redirectUrl, + url: redirectUrl.value, }) } }, 1000) @@ -74,40 +89,5 @@ onUnmounted(() => { diff --git a/src/pages/Login/user-register/components/CodeInput.scss b/src/pages/Login/user-register/components/CodeInput.scss new file mode 100644 index 0000000..9641dc9 --- /dev/null +++ b/src/pages/Login/user-register/components/CodeInput.scss @@ -0,0 +1,54 @@ +@import '@/styles/variables.scss'; + +.code-input { + display: flex; + align-items: center; + width: 100%; + height: 96rpx; + padding: 0 16rpx 0 32rpx; + box-sizing: border-box; + background: $color-bg-input; + border-radius: 48rpx; +} + +.code-input__icon { + flex-shrink: 0; + width: 40rpx; + height: 40rpx; + margin-right: 20rpx; +} + +.code-input__field { + flex: 1; + height: 96rpx; + font-size: 30rpx; + color: $color-text-primary; + background: transparent; +} + +.code-input__placeholder { + font-size: 30rpx; + color: $color-text-placeholder; +} + +.code-input__btn { + display: flex; + flex-shrink: 0; + align-items: center; + justify-content: center; + height: 64rpx; + padding: 0 24rpx; + background: $color-primary; + border-radius: 32rpx; + + &--disabled { + opacity: 0.6; + } +} + +.code-input__btn-text { + font-size: 24rpx; + font-weight: 500; + color: #ffffff; + white-space: nowrap; +} diff --git a/src/pages/Login/user-register/components/CodeInput.vue b/src/pages/Login/user-register/components/CodeInput.vue index 1556e8f..4d009e6 100644 --- a/src/pages/Login/user-register/components/CodeInput.vue +++ b/src/pages/Login/user-register/components/CodeInput.vue @@ -66,58 +66,5 @@ function handleGetCode() { diff --git a/src/pages/Login/user-register/components/PasswordField.scss b/src/pages/Login/user-register/components/PasswordField.scss new file mode 100644 index 0000000..d1f1b01 --- /dev/null +++ b/src/pages/Login/user-register/components/PasswordField.scss @@ -0,0 +1,39 @@ +@import '@/styles/variables.scss'; + +.password-field { + display: flex; + align-items: center; + width: 100%; + height: 96rpx; + padding: 0 32rpx; + box-sizing: border-box; + background: $color-bg-input; + border-radius: 48rpx; +} + +.password-field__icon { + flex-shrink: 0; + width: 40rpx; + height: 40rpx; + margin-right: 20rpx; +} + +.password-field__field { + flex: 1; + height: 96rpx; + font-size: 30rpx; + color: $color-text-primary; + background: transparent; +} + +.password-field__placeholder { + font-size: 30rpx; + color: $color-text-placeholder; +} + +.password-field__eye { + flex-shrink: 0; + width: 40rpx; + height: 40rpx; + margin-left: 16rpx; +} diff --git a/src/pages/Login/user-register/components/PasswordField.vue b/src/pages/Login/user-register/components/PasswordField.vue index cd4dcb6..b5dd833 100644 --- a/src/pages/Login/user-register/components/PasswordField.vue +++ b/src/pages/Login/user-register/components/PasswordField.vue @@ -52,43 +52,5 @@ function toggleVisible() { diff --git a/src/pages/Login/user-register/components/PasswordStrength.scss b/src/pages/Login/user-register/components/PasswordStrength.scss new file mode 100644 index 0000000..8a8ce49 --- /dev/null +++ b/src/pages/Login/user-register/components/PasswordStrength.scss @@ -0,0 +1,59 @@ +.password-strength { + width: 100%; + margin-top: 16rpx; +} + +.password-strength__row { + display: flex; + align-items: center; +} + +.password-strength__bars { + display: flex; + flex: 1; + gap: 12rpx; +} + +.password-strength__bar { + flex: 1; + height: 8rpx; + background: #e8e8e8; + border-radius: 4rpx; +} + +.password-strength__label { + flex-shrink: 0; + margin-left: 16rpx; + font-size: 24rpx; + font-weight: 500; +} + +.password-strength__error { + display: flex; + align-items: center; + margin-top: 12rpx; +} + +.password-strength__error-icon { + display: flex; + flex-shrink: 0; + align-items: center; + justify-content: center; + width: 28rpx; + height: 28rpx; + margin-right: 8rpx; + // background: #ff4d4f; + border-radius: 6rpx; +} + +.password-strength__error-mark { + font-size: 20rpx; + font-weight: 700; + color: #ffffff; + line-height: 1; +} + +.password-strength__error-text { + font-size: 24rpx; + color: #ff4d4f; +} diff --git a/src/pages/Login/user-register/components/PasswordStrength.vue b/src/pages/Login/user-register/components/PasswordStrength.vue index 194c0cc..34a7258 100644 --- a/src/pages/Login/user-register/components/PasswordStrength.vue +++ b/src/pages/Login/user-register/components/PasswordStrength.vue @@ -57,63 +57,5 @@ const showIndicator = computed(() => props.password.length > 0) diff --git a/src/pages/Login/user-register/components/RegisterInput.scss b/src/pages/Login/user-register/components/RegisterInput.scss new file mode 100644 index 0000000..24b0c47 --- /dev/null +++ b/src/pages/Login/user-register/components/RegisterInput.scss @@ -0,0 +1,32 @@ +@import '@/styles/variables.scss'; + +.register-input { + display: flex; + align-items: center; + width: 100%; + height: 96rpx; + padding: 0 32rpx; + box-sizing: border-box; + background: $color-bg-input; + border-radius: 48rpx; +} + +.register-input__icon { + flex-shrink: 0; + width: 40rpx; + height: 40rpx; + margin-right: 20rpx; +} + +.register-input__field { + flex: 1; + height: 96rpx; + font-size: 30rpx; + color: $color-text-primary; + background: transparent; +} + +.register-input__placeholder { + font-size: 30rpx; + color: $color-text-placeholder; +} diff --git a/src/pages/Login/user-register/components/RegisterInput.vue b/src/pages/Login/user-register/components/RegisterInput.vue index 62d7361..7bd1e7a 100644 --- a/src/pages/Login/user-register/components/RegisterInput.vue +++ b/src/pages/Login/user-register/components/RegisterInput.vue @@ -42,36 +42,5 @@ function onInput(e: { detail: { value: string } }) { diff --git a/src/pages/Login/user-register/index.scss b/src/pages/Login/user-register/index.scss new file mode 100644 index 0000000..8cecafc --- /dev/null +++ b/src/pages/Login/user-register/index.scss @@ -0,0 +1,131 @@ +@import '@/styles/variables.scss'; + +.register-page { + display: flex; + flex-direction: column; + min-height: 100vh; + padding: 0 64rpx; + background: $color-bg-page; +} + +.register-page__header { + padding-top: 120rpx; + text-align: center; +} + +.register-page__title { + display: block; + font-size: 56rpx; + font-weight: 700; + color: $color-text-primary; + letter-spacing: 2rpx; +} + +.register-page__subtitle { + display: block; + margin-top: 16rpx; + font-size: 28rpx; + font-weight: 400; + color: $color-text-secondary; +} + +.register-page__form { + width: 100%; + margin-top: 80rpx; + box-sizing: border-box; +} + +.register-page__field { + width: 100%; + margin-top: 24rpx; + box-sizing: border-box; + + &:first-child { + margin-top: 0; + } +} + +.register-page__agreement { + display: flex; + align-items: flex-start; + margin-top: 32rpx; +} + +.register-page__checkbox { + display: flex; + flex-shrink: 0; + align-items: center; + justify-content: center; + width: 32rpx; + height: 32rpx; + margin-top: 4rpx; + margin-right: 12rpx; + border: 2rpx solid #cccccc; + border-radius: 50%; + transition: all 0.2s; + + &--checked { + background: $color-primary; + border-color: $color-primary; + } +} + +.register-page__checkmark { + font-size: 20rpx; + font-weight: 700; + color: #ffffff; + line-height: 1; +} + +.register-page__agreement-text { + flex: 1; + font-size: 24rpx; + line-height: 1.6; +} + +.register-page__agreement-normal { + color: $color-text-secondary; +} + +.register-page__agreement-link { + color: $color-text-link; +} + +.register-page__submit { + display: flex; + align-items: center; + justify-content: center; + width: 100%; + height: 96rpx; + margin-top: 48rpx; + font-size: 32rpx; + font-weight: 600; + color: #ffffff; + background: $color-primary; + border: none; + border-radius: 48rpx; + line-height: 96rpx; + + &::after { + border: none; + } +} + +.register-page__footer { + display: flex; + align-items: center; + justify-content: center; + margin-top: auto; + padding: 60rpx 0 calc(60rpx + env(safe-area-inset-bottom)); +} + +.register-page__footer-normal { + font-size: 28rpx; + color: $color-text-secondary; +} + +.register-page__footer-link { + margin-left: 4rpx; + font-size: 28rpx; + color: $color-text-link; +} diff --git a/src/pages/Login/user-register/index.vue b/src/pages/Login/user-register/index.vue index 621882f..7e1a595 100644 --- a/src/pages/Login/user-register/index.vue +++ b/src/pages/Login/user-register/index.vue @@ -151,135 +151,5 @@ function handleUserAgreement() { diff --git a/src/pages/Login/user-sms-login/components/CodeInput.scss b/src/pages/Login/user-sms-login/components/CodeInput.scss new file mode 100644 index 0000000..9641dc9 --- /dev/null +++ b/src/pages/Login/user-sms-login/components/CodeInput.scss @@ -0,0 +1,54 @@ +@import '@/styles/variables.scss'; + +.code-input { + display: flex; + align-items: center; + width: 100%; + height: 96rpx; + padding: 0 16rpx 0 32rpx; + box-sizing: border-box; + background: $color-bg-input; + border-radius: 48rpx; +} + +.code-input__icon { + flex-shrink: 0; + width: 40rpx; + height: 40rpx; + margin-right: 20rpx; +} + +.code-input__field { + flex: 1; + height: 96rpx; + font-size: 30rpx; + color: $color-text-primary; + background: transparent; +} + +.code-input__placeholder { + font-size: 30rpx; + color: $color-text-placeholder; +} + +.code-input__btn { + display: flex; + flex-shrink: 0; + align-items: center; + justify-content: center; + height: 64rpx; + padding: 0 24rpx; + background: $color-primary; + border-radius: 32rpx; + + &--disabled { + opacity: 0.6; + } +} + +.code-input__btn-text { + font-size: 24rpx; + font-weight: 500; + color: #ffffff; + white-space: nowrap; +} diff --git a/src/pages/Login/user-sms-login/components/CodeInput.vue b/src/pages/Login/user-sms-login/components/CodeInput.vue index 1556e8f..4d009e6 100644 --- a/src/pages/Login/user-sms-login/components/CodeInput.vue +++ b/src/pages/Login/user-sms-login/components/CodeInput.vue @@ -66,58 +66,5 @@ function handleGetCode() { diff --git a/src/pages/Login/user-sms-login/components/LoginInput.scss b/src/pages/Login/user-sms-login/components/LoginInput.scss new file mode 100644 index 0000000..f954a4c --- /dev/null +++ b/src/pages/Login/user-sms-login/components/LoginInput.scss @@ -0,0 +1,32 @@ +@import '@/styles/variables.scss'; + +.login-input { + display: flex; + align-items: center; + width: 100%; + height: 96rpx; + padding: 0 32rpx; + box-sizing: border-box; + background: $color-bg-input; + border-radius: 48rpx; +} + +.login-input__icon { + flex-shrink: 0; + width: 40rpx; + height: 40rpx; + margin-right: 20rpx; +} + +.login-input__field { + flex: 1; + height: 96rpx; + font-size: 30rpx; + color: $color-text-primary; + background: transparent; +} + +.login-input__placeholder { + font-size: 30rpx; + color: $color-text-placeholder; +} diff --git a/src/pages/Login/user-sms-login/components/LoginInput.vue b/src/pages/Login/user-sms-login/components/LoginInput.vue index c4f8574..f0554ce 100644 --- a/src/pages/Login/user-sms-login/components/LoginInput.vue +++ b/src/pages/Login/user-sms-login/components/LoginInput.vue @@ -42,36 +42,5 @@ function onInput(e: { detail: { value: string } }) { diff --git a/src/pages/Login/user-sms-login/index.scss b/src/pages/Login/user-sms-login/index.scss new file mode 100644 index 0000000..f5dada1 --- /dev/null +++ b/src/pages/Login/user-sms-login/index.scss @@ -0,0 +1,181 @@ +@import '@/styles/variables.scss'; + +.sms-login-page { + display: flex; + flex-direction: column; + min-height: 100vh; + padding: 0 64rpx; + background: $color-bg-page; +} + +.sms-login-page__header { + padding-top: 120rpx; + text-align: center; +} + +.sms-login-page__title { + display: block; + font-size: 56rpx; + font-weight: 700; + color: $color-text-primary; + letter-spacing: 2rpx; +} + +.sms-login-page__subtitle { + display: block; + margin-top: 16rpx; + font-size: 28rpx; + font-weight: 400; + color: $color-text-secondary; +} + +.sms-login-page__form { + width: 100%; + margin-top: 80rpx; + box-sizing: border-box; +} + +.sms-login-page__code-group { + margin-top: 24rpx; +} + +.sms-login-page__agreement { + display: flex; + align-items: flex-start; + margin-top: 32rpx; +} + +.sms-login-page__checkbox { + display: flex; + flex-shrink: 0; + align-items: center; + justify-content: center; + width: 32rpx; + height: 32rpx; + margin-top: 4rpx; + margin-right: 12rpx; + border: 2rpx solid #cccccc; + border-radius: 50%; + transition: all 0.2s; + + &--checked { + background: $color-primary; + border-color: $color-primary; + } +} + +.sms-login-page__checkmark { + font-size: 20rpx; + font-weight: 700; + color: #ffffff; + line-height: 1; +} + +.sms-login-page__agreement-text { + flex: 1; + font-size: 24rpx; + line-height: 1.6; +} + +.sms-login-page__agreement-normal { + color: $color-text-secondary; +} + +.sms-login-page__agreement-link { + color: $color-text-link; +} + +.sms-login-page__submit { + display: flex; + align-items: center; + justify-content: center; + width: 100%; + height: 96rpx; + margin-top: 48rpx; + font-size: 32rpx; + font-weight: 600; + color: #ffffff; + background: $color-primary; + border: none; + border-radius: 48rpx; + line-height: 96rpx; + + &::after { + border: none; + } +} + +.sms-login-page__other { + flex: 1; + display: flex; + flex-direction: column; + align-items: center; + justify-content: center; + padding: 60rpx 0; +} + +.sms-login-page__divider { + display: flex; + align-items: center; + width: 100%; +} + +.sms-login-page__divider-line { + flex: 1; + height: 1rpx; + background: #e8e8e8; +} + +.sms-login-page__divider-text { + padding: 0 24rpx; + font-size: 24rpx; + color: $color-text-secondary; + white-space: nowrap; +} + +.sms-login-page__password { + display: flex; + flex-direction: column; + align-items: center; + width: fit-content; + margin-top: 48rpx; +} + +.sms-login-page__password-icon-wrap { + display: flex; + align-items: center; + justify-content: center; + width: 96rpx; + height: 96rpx; + background: #B6CDFF; + border-radius: 50%; +} + +.sms-login-page__password-icon { + width: 48rpx; + height: 48rpx; +} + +.sms-login-page__password-text { + margin-top: 16rpx; + font-size: 24rpx; + color: #999999; +} + +.sms-login-page__footer { + display: flex; + align-items: center; + justify-content: center; + padding-bottom: calc(60rpx + env(safe-area-inset-bottom)); +} + +.sms-login-page__footer-normal { + font-size: 28rpx; + color: $color-text-secondary; +} + +.sms-login-page__footer-link { + margin-left: 4rpx; + font-size: 28rpx; + color: $color-text-link; +} diff --git a/src/pages/Login/user-sms-login/index.vue b/src/pages/Login/user-sms-login/index.vue index 9714164..c4b4818 100644 --- a/src/pages/Login/user-sms-login/index.vue +++ b/src/pages/Login/user-sms-login/index.vue @@ -154,185 +154,5 @@ function handleUserAgreement() { diff --git a/src/pages/case-library/components/CaseCard.scss b/src/pages/case-library/components/CaseCard.scss new file mode 100644 index 0000000..b640642 --- /dev/null +++ b/src/pages/case-library/components/CaseCard.scss @@ -0,0 +1,87 @@ +@import '@/styles/variables.scss'; + +.case-card { + padding: 0 0 28rpx; + margin-bottom: 24rpx; + background: $color-bg-page; + border-radius: 20rpx; + overflow: hidden; +} + +.case-card__cover-wrap { + position: relative; + height: 320rpx; + overflow: hidden; +} + +.case-card__cover { + width: 100%; + height: 100%; +} + +.case-card__tag { + position: absolute; + top: 20rpx; + left: 20rpx; + padding: 6rpx 16rpx; + font-size: 22rpx; + color: #ffffff; + background: $color-primary; + border-radius: 8rpx; +} + +.case-card__favorite { + position: absolute; + top: 20rpx; + right: 20rpx; + display: flex; + align-items: center; + justify-content: center; + width: 56rpx; + height: 56rpx; + background: rgba(255, 255, 255, 0.92); + border-radius: 50%; +} + +.case-card__favorite-icon { + width: 32rpx; + height: 32rpx; +} + +.case-card__title { + display: block; + padding: 24rpx 24rpx 0; + font-size: 32rpx; + font-weight: 600; + color: $color-text-primary; +} + +.case-card__meta { + padding: 20rpx 24rpx 0; +} + +.case-card__meta-row { + display: flex; + margin-bottom: 16rpx; + + &:last-child { + margin-bottom: 0; + } +} + +.case-card__meta-item { + display: flex; + flex: 1; + flex-direction: column; +} + +.case-card__meta-label { + font-size: 22rpx; + color: $color-text-secondary; +} + +.case-card__meta-value { + margin-top: 8rpx; + font-size: 24rpx; + color: $color-text-primary; +} diff --git a/src/pages/case-library/components/CaseCard.vue b/src/pages/case-library/components/CaseCard.vue index 9e7747e..c9605fe 100644 --- a/src/pages/case-library/components/CaseCard.vue +++ b/src/pages/case-library/components/CaseCard.vue @@ -95,91 +95,5 @@ const emit = defineEmits<{ diff --git a/src/pages/case-library/components/CaseFilterPanel.scss b/src/pages/case-library/components/CaseFilterPanel.scss new file mode 100644 index 0000000..3183099 --- /dev/null +++ b/src/pages/case-library/components/CaseFilterPanel.scss @@ -0,0 +1,213 @@ +@import '@/styles/variables.scss'; + +.case-filter-panel { + position: fixed; + top: 0; + right: 0; + bottom: 0; + left: 0; + z-index: 300; +} + +.case-filter-panel__mask { + position: absolute; + top: 0; + right: 0; + bottom: 0; + left: 0; + background: rgba(0, 0, 0, 0.45); +} + +.case-filter-panel__sheet { + position: absolute; + right: 0; + bottom: 0; + left: 0; + display: flex; + flex-direction: column; + max-height: 78vh; + background: $color-bg-page; + border-radius: 24rpx 24rpx 0 0; +} + +.case-filter-panel__header { + display: flex; + align-items: center; + justify-content: space-between; + flex-shrink: 0; + padding: 28rpx 32rpx 20rpx; +} + +.case-filter-panel__title-wrap, +.case-filter-panel__reset { + display: flex; + align-items: center; +} + +.case-filter-panel__title-icon { + width: 28rpx; + height: 28rpx; + margin-right: 10rpx; +} + +.case-filter-panel__title { + font-size: 32rpx; + font-weight: 600; + color: $color-text-primary; +} + +.case-filter-panel__reset-icon { + margin-right: 6rpx; + font-size: 28rpx; + color: $color-primary; +} + +.case-filter-panel__reset-text { + font-size: 26rpx; + color: $color-primary; +} + +.case-filter-panel__body { + flex: 1; + min-height: 0; + padding: 0 32rpx; + box-sizing: border-box; +} + +.case-filter-panel__section { + margin-bottom: 28rpx; +} + +.case-filter-panel__section-title { + display: block; + margin-bottom: 20rpx; + font-size: 28rpx; + font-weight: 600; + color: $color-text-primary; +} + +.case-filter-panel__chips { + display: flex; + flex-wrap: wrap; + gap: 16rpx; +} + +.case-filter-panel__chip { + padding: 14rpx 24rpx; + font-size: 24rpx; + color: $color-text-primary; + background: $color-bg-section; + border-radius: 999rpx; + + &--active { + color: $color-primary; + background: $color-primary-light; + } +} + +.case-filter-panel__date-row { + display: flex; + align-items: center; + margin-top: 20rpx; +} + +.case-filter-panel__date-field { + display: flex; + align-items: center; + justify-content: center; + min-width: 220rpx; + height: 72rpx; + padding: 0 20rpx; + background: $color-bg-section; + border-radius: 999rpx; +} + +.case-filter-panel__date-placeholder { + color: $color-text-placeholder; +} + +.case-filter-panel__date-separator { + margin: 0 16rpx; + font-size: 24rpx; + color: $color-text-secondary; +} + +.case-filter-panel__selected { + flex-shrink: 0; + margin: 0 32rpx 20rpx; + padding: 20rpx 24rpx; + background: $color-bg-section; + border-radius: 16rpx; +} + +.case-filter-panel__selected-header { + display: flex; + align-items: center; + justify-content: space-between; + margin-bottom: 16rpx; +} + +.case-filter-panel__selected-title { + font-size: 24rpx; + color: $color-text-secondary; +} + +.case-filter-panel__selected-clear { + font-size: 24rpx; + color: $color-primary; +} + +.case-filter-panel__selected-tags { + display: flex; + flex-wrap: wrap; + gap: 12rpx; +} + +.case-filter-panel__tag { + display: flex; + align-items: center; + padding: 8rpx 16rpx; + background: $color-primary-light; + border-radius: 999rpx; +} + +.case-filter-panel__tag-text { + font-size: 22rpx; + color: $color-primary; +} + +.case-filter-panel__tag-close { + margin-left: 8rpx; + font-size: 24rpx; + line-height: 1; + color: $color-primary; +} + +.case-filter-panel__footer { + display: flex; + gap: 20rpx; + flex-shrink: 0; + padding: 16rpx 32rpx calc(24rpx + env(safe-area-inset-bottom)); +} + +.case-filter-panel__btn { + display: flex; + flex: 1; + align-items: center; + justify-content: center; + height: 88rpx; + font-size: 30rpx; + font-weight: 600; + border-radius: 44rpx; + + &--cancel { + color: $color-primary; + background: #ffffff; + border: 2rpx solid $color-primary; + } + + &--confirm { + color: #ffffff; + background: $color-primary; + } +} diff --git a/src/pages/case-library/components/CaseFilterPanel.vue b/src/pages/case-library/components/CaseFilterPanel.vue index 8a95a7e..a1e4058 100644 --- a/src/pages/case-library/components/CaseFilterPanel.vue +++ b/src/pages/case-library/components/CaseFilterPanel.vue @@ -312,217 +312,5 @@ function handleConfirm() { diff --git a/src/pages/case-library/components/LoadMoreFooter.scss b/src/pages/case-library/components/LoadMoreFooter.scss new file mode 100644 index 0000000..bb31e81 --- /dev/null +++ b/src/pages/case-library/components/LoadMoreFooter.scss @@ -0,0 +1,39 @@ +@import '@/styles/variables.scss'; + +.load-more-footer { + display: flex; + align-items: center; + justify-content: center; + padding: 32rpx 0 16rpx; +} + +.load-more-footer__loading { + display: flex; + align-items: center; +} + +.load-more-footer__spinner { + width: 32rpx; + height: 32rpx; + margin-right: 12rpx; + border: 4rpx solid #d6e4ff; + border-top-color: $color-primary; + border-radius: 50%; + animation: load-more-spin 0.8s linear infinite; +} + +.load-more-footer__text, +.load-more-footer__finished { + font-size: 24rpx; + color: $color-text-secondary; +} + +@keyframes load-more-spin { + from { + transform: rotate(0deg); + } + + to { + transform: rotate(360deg); + } +} diff --git a/src/pages/case-library/components/LoadMoreFooter.vue b/src/pages/case-library/components/LoadMoreFooter.vue index b6784ba..bce5776 100644 --- a/src/pages/case-library/components/LoadMoreFooter.vue +++ b/src/pages/case-library/components/LoadMoreFooter.vue @@ -41,43 +41,5 @@ const emit = defineEmits<{ diff --git a/src/pages/case-library/detail/index.scss b/src/pages/case-library/detail/index.scss new file mode 100644 index 0000000..fe6b40d --- /dev/null +++ b/src/pages/case-library/detail/index.scss @@ -0,0 +1,181 @@ +@import '@/styles/variables.scss'; + +.case-detail { + display: flex; + flex-direction: column; + min-height: 100vh; + background: $color-bg-section; +} + +.case-detail__navbar { + display: flex; + align-items: center; + justify-content: space-between; + flex-shrink: 0; + padding: calc(var(--status-bar-height, 44px) + 12rpx) 24rpx 20rpx; + background: $color-bg-page; +} + +.case-detail__back { + display: flex; + align-items: center; + justify-content: center; + width: 64rpx; + height: 64rpx; +} + +.case-detail__back-icon { + width: 40rpx; + height: 40rpx; +} + +.case-detail__navbar-title { + font-size: 34rpx; + font-weight: 600; + color: $color-text-primary; +} + +.case-detail__navbar-placeholder { + width: 64rpx; + height: 64rpx; +} + +.case-detail__scroll { + flex: 1; + height: 0; +} + +.case-detail__content { + padding: 24rpx 24rpx calc(32rpx + env(safe-area-inset-bottom)); +} + +.case-detail__hero { + padding: 32rpx 28rpx; + background: linear-gradient(135deg, #eef4ff 0%, #ffffff 60%); + border-radius: 20rpx; +} + +.case-detail__tag { + display: inline-block; + padding: 6rpx 16rpx; + font-size: 22rpx; + color: #ffffff; + background: $color-primary; + border-radius: 8rpx; +} + +.case-detail__title { + display: block; + margin-top: 20rpx; + font-size: 36rpx; + font-weight: 600; + line-height: 1.4; + color: $color-text-primary; +} + +.case-detail__section { + margin-top: 24rpx; + padding: 28rpx 24rpx; + background: $color-bg-page; + border-radius: 20rpx; + + &--last { + margin-bottom: 0; + } +} + +.case-detail__section-title { + display: block; + margin-bottom: 24rpx; + font-size: 32rpx; + font-weight: 600; + color: $color-text-primary; +} + +.case-detail__overview { + display: flex; + flex-wrap: wrap; +} + +.case-detail__overview-item { + display: flex; + flex-direction: column; + width: 33.33%; + margin-bottom: 24rpx; +} + +.case-detail__overview-label { + font-size: 22rpx; + color: $color-text-secondary; +} + +.case-detail__overview-value { + margin-top: 8rpx; + font-size: 26rpx; + color: $color-text-primary; +} + +.case-detail__image-placeholder { + height: 280rpx; + margin-bottom: 24rpx; + background: #e8eaed; + border-radius: 12rpx; +} + +.case-detail__paragraph { + display: block; + font-size: 28rpx; + line-height: 1.8; + color: $color-text-primary; +} + +.case-detail__attachments { + margin-top: 24rpx; + white-space: nowrap; +} + +.case-detail__attachments-inner { + display: inline-flex; + gap: 20rpx; + padding: 10rpx 10rpx 0 0; +} + +.case-detail__attachment { + position: relative; + display: flex; + flex-direction: column; + align-items: center; + width: 160rpx; + padding: 20rpx 16rpx; + background: $color-bg-section; + border-radius: 12rpx; +} + +.case-detail__attachment-remove { + position: absolute; + top: -10rpx; + right: -10rpx; + display: flex; + align-items: center; + justify-content: center; + width: 32rpx; + height: 32rpx; +} + +.case-detail__attachment-remove-icon { + width: 32rpx; + height: 32rpx; +} + +.case-detail__attachment-icon { + width: 64rpx; + height: 64rpx; +} + +.case-detail__attachment-name { + margin-top: 12rpx; + font-size: 22rpx; + color: $color-text-primary; + text-align: center; + word-break: break-all; +} diff --git a/src/pages/case-library/detail/index.vue b/src/pages/case-library/detail/index.vue index 0b56a02..3bc5b73 100644 --- a/src/pages/case-library/detail/index.vue +++ b/src/pages/case-library/detail/index.vue @@ -161,185 +161,5 @@ function handleBack() { diff --git a/src/pages/case-library/favorites/index.scss b/src/pages/case-library/favorites/index.scss new file mode 100644 index 0000000..d5d8ad0 --- /dev/null +++ b/src/pages/case-library/favorites/index.scss @@ -0,0 +1,172 @@ +@import '@/styles/variables.scss'; + +.case-favorites { + display: flex; + flex-direction: column; + height: 100vh; + overflow: hidden; + background: $color-bg-section; +} + +.case-favorites__header { + flex-shrink: 0; + padding: calc(var(--status-bar-height, 44px) + 60rpx) 24rpx 0; + background: $color-bg-page; +} + +.case-favorites__navbar { + display: flex; + align-items: center; + justify-content: space-between; + padding-bottom: 28rpx; +} + +.case-favorites__back { + display: flex; + align-items: center; + justify-content: center; + width: 64rpx; + height: 64rpx; +} + +.case-favorites__back-icon { + width: 40rpx; + height: 40rpx; +} + +.case-favorites__title { + font-size: 36rpx; + font-weight: 600; + color: $color-text-primary; +} + +.case-favorites__navbar-placeholder { + width: 64rpx; + height: 64rpx; +} + +.case-favorites__search-row { + display: flex; + align-items: center; +} + +.case-favorites__search { + display: flex; + flex: 1; + align-items: center; + height: 72rpx; + padding: 0 24rpx; + background: $color-bg-section; + border-radius: 36rpx; +} + +.case-favorites__search-icon { + flex-shrink: 0; + width: 32rpx; + height: 32rpx; + margin-right: 12rpx; +} + +.case-favorites__search-input { + flex: 1; + font-size: 26rpx; + color: $color-text-primary; +} + +.case-favorites__search-placeholder { + color: $color-text-placeholder; +} + +.case-favorites__favorite-btn { + display: flex; + flex-shrink: 0; + align-items: center; + justify-content: center; + width: 72rpx; + height: 72rpx; + margin-left: 16rpx; +} + +.case-favorites__favorite-btn-icon { + width: 40rpx; + height: 40rpx; +} + +.case-favorites__tabs { + margin-top: 24rpx; + white-space: nowrap; +} + +.case-favorites__tabs-inner { + display: inline-flex; + gap: 32rpx; + padding-right: 24rpx; +} + +.case-favorites__tab { + flex-shrink: 0; + padding-bottom: 12rpx; + font-size: 28rpx; + color: $color-text-secondary; + + &--active { + font-weight: 600; + color: $color-text-primary; + border-bottom: 4rpx solid $color-primary; + } +} + +.case-favorites__quick-filters { + display: flex; + align-items: center; + gap: 24rpx; + margin-top: 20rpx; +} + +.case-favorites__quick-filter { + display: flex; + align-items: center; + gap: 4rpx; + font-size: 26rpx; + color: $color-text-primary; +} + +.case-favorites__quick-filter-arrow { + font-size: 20rpx; + color: $color-text-secondary; +} + +.case-favorites__filter { + display: flex; + align-items: center; + margin-left: auto; +} + +.case-favorites__filter-icon { + width: 28rpx; + height: 28rpx; + margin-left: 8rpx; +} + +.case-favorites__filter-text { + font-size: 26rpx; + color: #666666; +} + +.case-favorites__toolbar { + padding: 20rpx 0 24rpx; +} + +.case-favorites__count { + font-size: 24rpx; + color: $color-text-secondary; +} + +.case-favorites__scroll { + flex: 1; + min-height: 0; +} + +.case-favorites__list { + padding: 0 24rpx calc(32rpx + env(safe-area-inset-bottom)); +} diff --git a/src/pages/case-library/favorites/index.vue b/src/pages/case-library/favorites/index.vue index 6b39b6d..2dbe229 100644 --- a/src/pages/case-library/favorites/index.vue +++ b/src/pages/case-library/favorites/index.vue @@ -291,176 +291,5 @@ function showTimePicker() { diff --git a/src/pages/case-library/index.scss b/src/pages/case-library/index.scss new file mode 100644 index 0000000..281ee19 --- /dev/null +++ b/src/pages/case-library/index.scss @@ -0,0 +1,132 @@ +@import '@/styles/variables.scss'; + +.case-library { + display: flex; + flex-direction: column; + height: 100vh; + overflow: hidden; + background: $color-bg-section; +} + +.case-library__header { + flex-shrink: 0; + padding: calc(var(--status-bar-height, 44px) + 60rpx) 24rpx 0; + background: $color-bg-page; +} + +.case-library__title { + display: block; + font-size: 36rpx; + font-weight: 600; + color: $color-text-primary; + text-align: center; +} + +.case-library__search-row { + display: flex; + align-items: center; + margin-top: 24rpx; +} + +.case-library__search { + display: flex; + flex: 1; + align-items: center; + height: 72rpx; + padding: 0 24rpx; + background: $color-bg-section; + border-radius: 36rpx; +} + +.case-library__search-icon { + flex-shrink: 0; + width: 32rpx; + height: 32rpx; + margin-right: 12rpx; +} + +.case-library__search-input { + flex: 1; + font-size: 26rpx; + color: $color-text-primary; +} + +.case-library__search-placeholder { + color: $color-text-placeholder; +} + +.case-library__favorite-btn { + display: flex; + flex-shrink: 0; + align-items: center; + justify-content: center; + width: 72rpx; + height: 72rpx; + margin-left: 16rpx; +} + +.case-library__favorite-btn-icon { + width: 40rpx; + height: 40rpx; +} + +.case-library__tabs { + margin-top: 24rpx; + white-space: nowrap; +} + +.case-library__tabs-inner { + display: inline-flex; + gap: 32rpx; + padding-right: 24rpx; +} + +.case-library__tab { + flex-shrink: 0; + padding-bottom: 12rpx; + font-size: 28rpx; + color: $color-text-secondary; + + &--active { + font-weight: 600; + color: $color-text-primary; + border-bottom: 4rpx solid $color-primary; + } +} + +.case-library__toolbar { + display: flex; + align-items: center; + justify-content: space-between; + padding: 20rpx 0 24rpx; +} + +.case-library__count { + font-size: 24rpx; + color: $color-text-secondary; +} + +.case-library__filter { + display: flex; + align-items: center; +} + +.case-library__filter-icon { + width: 28rpx; + height: 28rpx; + margin-right: 8rpx; +} + +.case-library__filter-text { + font-size: 26rpx; + color: #666666; +} + +.case-library__scroll { + flex: 1; + min-height: 0; +} + +.case-library__list { + padding: 0 24rpx calc(140rpx + env(safe-area-inset-bottom)); +} diff --git a/src/pages/case-library/index.vue b/src/pages/case-library/index.vue index 07ba4c2..4fe105d 100644 --- a/src/pages/case-library/index.vue +++ b/src/pages/case-library/index.vue @@ -209,136 +209,5 @@ function handleCaseTap(id: string) { diff --git a/src/pages/home-index/business-detail/index.scss b/src/pages/home-index/business-detail/index.scss new file mode 100644 index 0000000..21a757a --- /dev/null +++ b/src/pages/home-index/business-detail/index.scss @@ -0,0 +1,192 @@ +@import '@/styles/variables.scss'; + +.business-detail { + display: flex; + flex-direction: column; + min-height: 100vh; + background: $color-bg-section; +} + +.business-detail__navbar { + display: flex; + align-items: center; + justify-content: space-between; + flex-shrink: 0; + padding: calc(var(--status-bar-height, 44px) + 12rpx) 24rpx 12rpx; + background: $color-bg-page; +} + +.business-detail__back { + display: flex; + align-items: center; + justify-content: center; + width: 64rpx; + height: 64rpx; +} + +.business-detail__back-icon { + width: 40rpx; + height: 40rpx; +} + +.business-detail__navbar-title { + font-size: 34rpx; + font-weight: 600; + color: $color-text-primary; +} + +.business-detail__navbar-placeholder { + width: 64rpx; + height: 64rpx; +} + +.business-detail__scroll { + flex: 1; + height: 0; +} + +.business-detail__hero { + position: relative; + margin: 20rpx 24rpx 0; + overflow: hidden; + border-radius: 20rpx; +} + +.business-detail__hero-bg { + position: absolute; + top: 0; + left: 0; + z-index: 0; + width: 100%; + height: 100%; +} + +.business-detail__hero-inner { + position: relative; + z-index: 1; + padding: 24rpx 24rpx 28rpx; +} + +.business-detail__hero-icon { + width: 96rpx; + height: 96rpx; +} + +.business-detail__hero-title { + display: block; + margin-top: 16rpx; + font-size: 32rpx; + font-weight: 600; + color: $color-text-primary; +} + +.business-detail__hero-subtitle { + display: block; + margin-top: 8rpx; + font-size: 24rpx; + line-height: 1.5; + color: #333333; +} + +.business-detail__section { + margin: 20rpx 24rpx 0; + padding: 28rpx 24rpx 32rpx; + background: $color-bg-page; + border-radius: 20rpx; +} + +.business-detail__section-title { + display: block; + margin-bottom: 28rpx; + font-size: 32rpx; + font-weight: 600; + color: $color-text-primary; +} + +.business-detail__type-row { + display: flex; + justify-content: space-between; +} + +.business-detail__type-item { + display: flex; + flex: 1; + flex-direction: column; + align-items: center; +} + +.business-detail__type-icon { + width: 91rpx; + height: 91rpx; +} + +.business-detail__type-label { + margin-top: 12rpx; + font-size: 22rpx; + color: $color-text-primary; + text-align: center; +} + +.business-detail__video { + position: relative; + display: flex; + align-items: center; + justify-content: center; + height: 360rpx; + overflow: hidden; + background: linear-gradient(135deg, #1a1a2e 0%, #16213e 50%, #0f3460 100%); + border-radius: 16rpx; +} + +.business-detail__video-play { + display: flex; + align-items: center; + justify-content: center; + width: 80rpx; + height: 80rpx; + background: rgba(255, 255, 255, 0.25); + border-radius: 50%; +} + +.business-detail__video-play-icon { + margin-left: 6rpx; + font-size: 32rpx; + color: #ffffff; +} + +.business-detail__content { + margin-top: 28rpx; +} + +.business-detail__paragraph { + display: block; + margin-bottom: 16rpx; + font-size: 28rpx; + line-height: 1.8; + color: $color-text-primary; + + &--title { + margin-top: 8rpx; + margin-bottom: 12rpx; + font-weight: 600; + } +} + +.business-detail__footer { + flex-shrink: 0; + padding: 16rpx 32rpx calc(16rpx + env(safe-area-inset-bottom)); + background: $color-bg-page; + border-top: 1rpx solid #f0f0f0; +} + +.business-detail__submit-btn { + display: flex; + align-items: center; + justify-content: center; + height: 88rpx; + font-size: 32rpx; + font-weight: 600; + color: #ffffff; + background: $color-primary; + border-radius: 44rpx; +} diff --git a/src/pages/home-index/business-detail/index.vue b/src/pages/home-index/business-detail/index.vue index 6ef4aeb..9c72922 100644 --- a/src/pages/home-index/business-detail/index.vue +++ b/src/pages/home-index/business-detail/index.vue @@ -140,196 +140,5 @@ function handleSubmit() { diff --git a/src/pages/home-index/components/HomeFloatingActions.scss b/src/pages/home-index/components/HomeFloatingActions.scss new file mode 100644 index 0000000..20a1990 --- /dev/null +++ b/src/pages/home-index/components/HomeFloatingActions.scss @@ -0,0 +1,60 @@ +@import '@/styles/variables.scss'; + +.home-floating-actions { + position: fixed; + right: 24rpx; + bottom: calc(160rpx + env(safe-area-inset-bottom)); + z-index: 120; + display: flex; + flex-direction: column; + align-items: flex-end; + gap: 20rpx; +} + +.home-floating-actions__item { + display: flex; + align-items: center; + height: 72rpx; + padding: 0 28rpx 0 12rpx; + background: #ffffff; + border-radius: 999rpx; + box-shadow: 0 8rpx 24rpx rgba(0, 0, 0, 0.1); +} + +.home-floating-actions__icon { + display: flex; + flex-shrink: 0; + align-items: center; + justify-content: center; + width: 48rpx; + height: 48rpx; + border-radius: 50%; + + &--submit { + background: #22c55e; + } + + &--service { + background: #e8f0ff; + } +} + +.home-floating-actions__plus { + font-size: 32rpx; + font-weight: 500; + line-height: 1; + color: #ffffff; +} + +.home-floating-actions__service-icon { + width: 32rpx; + height: 32rpx; +} + +.home-floating-actions__label { + margin-left: 16rpx; + font-size: 26rpx; + font-weight: 500; + color: $color-text-primary; + white-space: nowrap; +} diff --git a/src/pages/home-index/components/HomeFloatingActions.vue b/src/pages/home-index/components/HomeFloatingActions.vue index 8a0c876..9ef44be 100644 --- a/src/pages/home-index/components/HomeFloatingActions.vue +++ b/src/pages/home-index/components/HomeFloatingActions.vue @@ -47,65 +47,5 @@ function handleCustomerService() { diff --git a/src/pages/home-index/components/ProjectCard.scss b/src/pages/home-index/components/ProjectCard.scss new file mode 100644 index 0000000..37ed3a9 --- /dev/null +++ b/src/pages/home-index/components/ProjectCard.scss @@ -0,0 +1,123 @@ +@import '@/styles/variables.scss'; + +.project-card { + position: relative; + margin-top: 20rpx; + overflow: hidden; + border-radius: 20rpx; +} + +.project-card__bg { + position: absolute; + top: 0; + left: 0; + z-index: 0; + width: 100%; + height: 100%; +} + +.project-card__inner { + position: relative; + z-index: 1; + padding: 28rpx; +} + +.project-card__header { + display: flex; + align-items: flex-start; + justify-content: space-between; +} + +.project-card__title { + flex: 1; + padding-right: 16rpx; + font-size: 30rpx; + font-weight: 600; + color: $color-text-primary; +} + +.project-card__status { + flex-shrink: 0; + font-size: 24rpx; + color: $color-text-secondary; +} + +.project-card__meta { + display: flex; + align-items: center; + margin-top: 16rpx; +} + +.project-card__meta-info { + display: flex; + flex: 1; + align-items: center; + justify-content: space-between; + min-width: 0; + margin-left: 12rpx; +} + +.project-card__tag { + flex-shrink: 0; + padding: 4rpx 12rpx; + font-size: 20rpx; + border-radius: 6rpx; + font-weight: 500; + width: 100rpx; + text-align: center; + height: 20rpx; + line-height: 20rpx; + + &--orange { + color: #875045; + background: #FFF1EA; + } +} + +.project-card__no { + flex: 1; + min-width: 0; + font-size: 22rpx; + color: #666666; + white-space: nowrap; + overflow: hidden; + text-overflow: ellipsis; +} + +.project-card__progress-value { + flex-shrink: 0; + margin-left: 12rpx; + font-size: 24rpx; + color: #666666; +} + +.project-card__progress-bar { + height: 12rpx; + margin-top: 24rpx; + overflow: hidden; + background: #eef2ff; + border-radius: 6rpx; +} + +.project-card__progress-fill { + height: 100%; + background: $color-primary; + border-radius: 6rpx; +} + +.project-card__footer { + display: flex; + align-items: center; + justify-content: space-between; + margin-top: 20rpx; +} + +.project-card__time { + font-size: 22rpx; + color: #666666; +} + +.project-card__detail { + font-size: 24rpx; + color: #666666; +} diff --git a/src/pages/home-index/components/ProjectCard.vue b/src/pages/home-index/components/ProjectCard.vue index 9f4126d..ad4d018 100644 --- a/src/pages/home-index/components/ProjectCard.vue +++ b/src/pages/home-index/components/ProjectCard.vue @@ -61,127 +61,5 @@ defineProps<{ diff --git a/src/pages/home-index/components/QuickEntryEditor.scss b/src/pages/home-index/components/QuickEntryEditor.scss new file mode 100644 index 0000000..eb042c1 --- /dev/null +++ b/src/pages/home-index/components/QuickEntryEditor.scss @@ -0,0 +1,137 @@ +@import '@/styles/variables.scss'; + +.quick-entry-editor { + position: fixed; + top: 0; + right: 0; + bottom: 0; + left: 0; + z-index: 200; + display: flex; + align-items: center; + justify-content: center; + padding: 0 40rpx; + box-sizing: border-box; +} + +.quick-entry-editor__mask { + position: absolute; + top: 0; + right: 0; + bottom: 0; + left: 0; + background: rgba(0, 0, 0, 0.45); +} + +.quick-entry-editor__panel { + position: relative; + z-index: 1; + display: flex; + flex-direction: column; + width: 100%; + max-height: 80vh; + overflow: hidden; + background: $color-bg-page; + border-radius: 24rpx; + box-shadow: 0 16rpx 48rpx rgba(0, 0, 0, 0.12); +} + +.quick-entry-editor__header { + display: flex; + align-items: center; + justify-content: space-between; + flex-shrink: 0; + padding: 32rpx 32rpx 24rpx; +} + +.quick-entry-editor__title { + font-size: 34rpx; + font-weight: 600; + color: $color-text-primary; +} + +.quick-entry-editor__close { + width: 48rpx; + font-size: 40rpx; + line-height: 1; + color: $color-text-secondary; + text-align: right; +} + +.quick-entry-editor__body { + flex: 1; + max-height: calc(80vh - 100rpx); + padding: 0 24rpx 32rpx; + box-sizing: border-box; +} + +.quick-entry-editor__section-title { + display: block; + margin: 32rpx 8rpx 24rpx; + font-size: 30rpx; + font-weight: 600; + color: $color-text-primary; +} + +.quick-entry-editor__grid { + display: flex; + flex-wrap: wrap; + + &--pinned { + justify-content: space-between; + padding: 0 8rpx; + } + + &--other { + row-gap: 28rpx; + padding: 0 8rpx; + } +} + +.quick-entry-editor__item { + display: flex; + flex-direction: column; + align-items: center; + width: 20%; +} + +.quick-entry-editor__icon-wrap { + position: relative; + display: flex; + align-items: center; + justify-content: center; + width: 88rpx; + height: 88rpx; +} + +.quick-entry-editor__icon { + width: 72rpx; + height: 72rpx; +} + +.quick-entry-editor__badge { + position: absolute; + top: -4rpx; + right: -4rpx; + display: flex; + align-items: center; + justify-content: center; + width: 32rpx; + height: 32rpx; + background: #c8cdd4; + border-radius: 50%; +} + +.quick-entry-editor__badge-text { + font-size: 22rpx; + font-weight: 600; + line-height: 1; + color: #ffffff; +} + +.quick-entry-editor__label { + margin-top: 12rpx; + font-size: 22rpx; + color: $color-text-primary; + text-align: center; +} diff --git a/src/pages/home-index/components/QuickEntryEditor.vue b/src/pages/home-index/components/QuickEntryEditor.vue index a42d2c4..432ec7f 100644 --- a/src/pages/home-index/components/QuickEntryEditor.vue +++ b/src/pages/home-index/components/QuickEntryEditor.vue @@ -104,141 +104,5 @@ const emit = defineEmits<{ diff --git a/src/pages/home-index/components/ServiceCard.scss b/src/pages/home-index/components/ServiceCard.scss new file mode 100644 index 0000000..d7066fd --- /dev/null +++ b/src/pages/home-index/components/ServiceCard.scss @@ -0,0 +1,75 @@ +.service-card { + position: relative; + display: flex; + height: 240rpx; + padding: 28rpx 24rpx 24rpx; + overflow: hidden; + border-radius: 20rpx; + box-sizing: border-box; + + &--with-illus { + overflow: visible; + } + + &--blue { + background: linear-gradient(180deg, #D3E1FC 0%, #FFFFFF 100%); + } + + &--green { + background: linear-gradient( 180deg, #B7EDEA 0%, #FFFFFF 100%); + } + + &--pink { + background: linear-gradient( 180deg, #FFECE1 0%, #FFFFFF 100%); + } + + &--orange { + background: linear-gradient( 180deg, #F7D3C6 0%, #FFFFFF 100%); + } + + &--clickable { + cursor: pointer; + } +} + +.service-card__illus { + position: absolute; + top: -36rpx; + right: -10rpx; + z-index: 2; + width: 152rpx; + height: 152rpx; + pointer-events: none; +} + +.service-card__content { + position: relative; + z-index: 1; + display: flex; + flex: 1; + flex-direction: column; + width: 100%; +} + +.service-card__title { + font-size: 30rpx; + font-weight: 600; + color: #1a1a1a; +} + +.service-card__desc { + margin-top: 12rpx; + font-size: 22rpx; + line-height: 1.45; + color: #666666; +} + +.service-card--with-illus .service-card__desc { + margin-top: 28rpx; +} + +.service-card__link { + margin-top: auto; + font-size: 22rpx; + color: #2563EB; +} diff --git a/src/pages/home-index/components/ServiceCard.vue b/src/pages/home-index/components/ServiceCard.vue index 0e3d0b3..58ed937 100644 --- a/src/pages/home-index/components/ServiceCard.vue +++ b/src/pages/home-index/components/ServiceCard.vue @@ -46,79 +46,5 @@ function handleTap() { diff --git a/src/pages/home-index/index.scss b/src/pages/home-index/index.scss new file mode 100644 index 0000000..5de53c2 --- /dev/null +++ b/src/pages/home-index/index.scss @@ -0,0 +1,270 @@ +@import '@/styles/variables.scss'; + +.home { + display: flex; + flex-direction: column; + min-height: 100vh; + background: $color-bg-section; +} + +.home__header { + position: relative; + flex-shrink: 0; + overflow: hidden; + background: $color-home-header; + height: 360rpx; +} + +.home__header-bg { + position: absolute; + top: 0; + left: 0; + z-index: 0; + width: 100%; + height: 100%; +} + +.home__header-inner { + position: relative; + z-index: 1; + padding: calc(var(--status-bar-height, 44px) + 16rpx) 32rpx 48rpx; +} + +.home__header-top { + display: flex; + align-items: center; + justify-content: space-between; + margin-top:85rpx +} + +.home__brand { + display: flex; + flex: 1; + align-items: center; + min-width: 0; +} + +.home__logo { + flex-shrink: 0; + width: 76.34rpx; + height: 76.34rpx; + padding: 8rpx; + border-radius: 12rpx; + box-sizing: border-box; +} + +.home__brand-name { + margin-left: 16rpx; + font-size: 26rpx; + font-weight: 500; + color: #ffffff; + overflow: hidden; + text-overflow: ellipsis; + white-space: nowrap; +} + +.home__message-btn { + display: flex; + flex-shrink: 0; + align-items: center; + justify-content: center; + width: 64rpx; + height: 64rpx; + margin-left: 16rpx; + border-radius: 16rpx; +} + +.home__message-icon { + width: 57.25rpx; + height: 57.25rpx; +} + +.home__greeting-row { + display: flex; + align-items: center; + margin-top: 30rpx; +} + +.home__greeting { + font-size: 52rpx; + font-weight: 700; + color: #ffffff; +} + +.home__hi-badge { + display: flex; + align-items: center; + justify-content: center; + width: 45.8rpx; + height: 45.8rpx; + margin-left: 16rpx; + border-radius: 50%; +} + +.home__hi-text { + font-size: 22rpx; + font-weight: 600; + color: #ffffff; + text-transform: lowercase; +} + +.home__subtitle { + display: block; + margin-top: 12rpx; + font-size: 26rpx; + color: rgba(255, 255, 255, 0.85); +} + +.home__body { + flex: 1; + background: transparent; +} + +.home__content { + min-height: 100%; + margin-top: 24rpx; + padding: 20rpx 20rpx calc(140rpx + env(safe-area-inset-bottom)); +} + +.home__section { + margin-bottom: 20rpx; + height: 600rpx; + width: 711.83rpx; + background: $color-bg-page; + border-radius: 20rpx; + padding-top: 20rpx +} + +.home__sections { + margin-bottom: 20rpx; + height: 210rpx; + width: 711.83rpx; + background: $color-bg-page; + border-radius: 20rpx; + padding-top: 20rpx +} + +.home__sectionss { + margin-bottom: 20rpx; + width: 711.83rpx; + background: $color-bg-page; + border-radius: 20rpx; + padding-top: 20rpx +} + +.home__section--last { + margin-bottom: 0; +} + +.home__section-header { + display: flex; + align-items: center; + justify-content: space-between; + margin-bottom: 24rpx; +} + +.home__section-title { + font-size: 32rpx; + font-weight: 500; + color: $color-text-primary; + margin-left: 30rpx; + // margin-top: 20rpx; +} + +.home__section-action { + font-size: 26rpx; + color: #666666 ; + margin-right: 20rpx; +} + +.home__service-grid { + display: grid; + grid-template-columns: 1fr 1fr; + gap: 20rpx; + margin-top: 24rpx; + padding: 24rpx 20rpx 0; + overflow: visible; +} + +.home__quick-row { + display: flex; + justify-content: space-between; +} + +.home__quick-item { + display: flex; + flex: 1; + flex-direction: column; + align-items: center; +} + +.home__quick-icon { + width: 60rpx; + height: 60rpx; +} + +.home__quick-label { + margin-top: 12rpx; + font-size: 22rpx; + color: $color-text-primary; + text-align: center; +} + +.home__stats-row { + display: flex; + gap: 20rpx; + padding: 0 20rpx; +} + +.home__stat-card { + display: flex; + flex: 1; + flex-direction: column; + align-items: center; + justify-content: center; + padding: 32rpx 24rpx; + border-radius: 16rpx; + text-align: center; + + &--blue { + background: linear-gradient(180deg, #D3E1FC 0%, #FFFFFF 100%); + } + + &--orange { + background: linear-gradient(180deg, #FFECE1 0%, #FFFFFF 100%); + } +} + +.home__stat-value { + display: flex; + align-items: baseline; + justify-content: center; +} + +.home__stat-num { + font-size: 56rpx; + font-weight: 700; + line-height: 1; + color: $color-text-primary; +} + +.home__stat-unit { + margin-left: 4rpx; + font-size: 28rpx; + font-weight: 500; + color: $color-text-primary; +} + +.home__stat-label { + margin-top: 12rpx; + font-size: 24rpx; + color: #333333; +} + +.home__recent-title { + display: block; + margin-top: 32rpx; + font-size: 28rpx; + font-weight: 600; + color: $color-text-primary; +} diff --git a/src/pages/home-index/index.vue b/src/pages/home-index/index.vue index 9646111..114f0e5 100644 --- a/src/pages/home-index/index.vue +++ b/src/pages/home-index/index.vue @@ -244,274 +244,5 @@ const projects: ProjectItem[] = [ diff --git a/src/pages/home-index/requirement-submit/index.scss b/src/pages/home-index/requirement-submit/index.scss new file mode 100644 index 0000000..a28fb4c --- /dev/null +++ b/src/pages/home-index/requirement-submit/index.scss @@ -0,0 +1,353 @@ +@import '@/styles/variables.scss'; + +.requirement-submit { + display: flex; + flex-direction: column; + min-height: 100vh; + background: $color-bg-section; +} + +.requirement-submit__navbar { + position: relative; + z-index: 30; + display: flex; + align-items: center; + justify-content: space-between; + flex-shrink: 0; + padding: calc(var(--status-bar-height, 44px) + 12rpx) 24rpx 12rpx; + background: $color-bg-page; +} + +.requirement-submit__back { + display: flex; + align-items: center; + justify-content: center; + width: 64rpx; + height: 64rpx; +} + +.requirement-submit__back-icon { + width: 40rpx; + height: 40rpx; +} + +.requirement-submit__navbar-title { + font-size: 34rpx; + font-weight: 600; + color: $color-text-primary; +} + +.requirement-submit__navbar-placeholder { + width: 64rpx; + height: 64rpx; +} + +.requirement-submit__scroll { + flex: 1; + height: 0; + padding: 20rpx 24rpx; + box-sizing: border-box; +} + +.requirement-submit__card { + padding: 28rpx 24rpx; + margin-bottom: 20rpx; + background: $color-bg-page; + border-radius: 20rpx; + + &--dropdown { + position: relative; + z-index: 20; + overflow: visible; + } +} + +.requirement-submit__field { + margin-bottom: 28rpx; + + &:last-child { + margin-bottom: 0; + } +} + +.requirement-submit__label { + display: block; + margin-bottom: 16rpx; + font-size: 28rpx; + font-weight: 500; + color: $color-text-primary; +} + +.requirement-submit__required { + color: #ff4d4f; +} + +.requirement-submit__hint { + display: block; + margin-bottom: 16rpx; + font-size: 24rpx; + color: $color-text-secondary; +} + +.requirement-submit__input { + width: 100%; + font-size: 28rpx; + color: $color-text-primary; + + &--box { + height: 80rpx; + padding: 0 24rpx; + background: $color-bg-page; + border: 1rpx solid #e8eaef; + border-radius: 12rpx; + box-sizing: border-box; + } + + &--cycle { + flex: 1; + } +} + +.requirement-submit__placeholder { + color: $color-text-placeholder; +} + +.requirement-submit__select-wrap { + position: relative; + z-index: 20; +} + +.requirement-submit__select { + display: flex; + align-items: center; + height: 80rpx; + padding: 0 24rpx; + background: $color-bg-page; + border: 1rpx solid #e8eaef; + border-radius: 12rpx; +} + +.requirement-submit__select-text { + flex: 1; + font-size: 28rpx; + color: $color-text-primary; + + &--placeholder { + color: $color-text-placeholder; + } +} + +.requirement-submit__select-arrow { + flex-shrink: 0; + margin-left: 12rpx; + font-size: 24rpx; + color: $color-text-secondary; + transition: transform 0.2s ease; + + &--open { + transform: rotate(180deg); + } +} + +.requirement-submit__dropdown { + position: absolute; + top: calc(100% + 8rpx); + right: 0; + left: 0; + z-index: 21; + overflow: hidden; + background: $color-bg-page; + border: 1rpx solid #e8eaef; + border-radius: 12rpx; + box-shadow: 0 8rpx 24rpx rgba(0, 0, 0, 0.08); +} + +.requirement-submit__dropdown-item { + padding: 24rpx; + font-size: 28rpx; + color: $color-text-primary; + border-bottom: 1rpx solid #f0f0f0; + + &:last-child { + border-bottom: none; + } + + &--active { + color: $color-primary; + background: $color-primary-light; + } +} + +.requirement-submit__dropdown-mask { + position: fixed; + top: 0; + right: 0; + bottom: 0; + left: 0; + z-index: 10; + background: transparent; +} + +.requirement-submit__textarea-wrap { + position: relative; + padding: 20rpx 24rpx 48rpx; + background: $color-bg-page; + border: 1rpx solid #e8eaef; + border-radius: 12rpx; +} + +.requirement-submit__textarea { + width: 100%; + min-height: 180rpx; + font-size: 28rpx; + line-height: 1.6; + color: $color-text-primary; + + &--remark { + min-height: 140rpx; + padding: 20rpx 24rpx; + background: $color-bg-page; + border: 1rpx solid #e8eaef; + border-radius: 12rpx; + box-sizing: border-box; + } +} + +.requirement-submit__counter { + position: absolute; + right: 24rpx; + bottom: 16rpx; + font-size: 22rpx; + color: $color-text-secondary; +} + +.requirement-submit__budget-row { + display: flex; + flex-wrap: wrap; + gap: 16rpx; +} + +.requirement-submit__budget-item { + padding: 14rpx 28rpx; + font-size: 26rpx; + color: $color-text-primary; + background: $color-bg-page; + border: 1rpx solid #e8eaef; + border-radius: 12rpx; + + &--active { + color: $color-primary; + background: $color-primary-light; + border-color: $color-primary-light; + } +} + +.requirement-submit__cycle-row { + display: flex; + align-items: center; +} + +.requirement-submit__cycle-unit { + flex-shrink: 0; + margin-left: 16rpx; + font-size: 28rpx; + color: $color-text-primary; +} + +.requirement-submit__attachment-row { + display: flex; + flex-wrap: wrap; + gap: 20rpx; +} + +.requirement-submit__attachment-item { + position: relative; + width: 120rpx; + height: 120rpx; +} + +.requirement-submit__attachment-thumb { + display: flex; + align-items: center; + justify-content: center; + width: 100%; + height: 100%; + background: #f8f9fb; + border: 1rpx solid #e8eaef; + border-radius: 12rpx; +} + +.requirement-submit__attachment-icon { + width: 72rpx; + height: 72rpx; +} + +.requirement-submit__attachment-remove { + position: absolute; + top: -10rpx; + right: -10rpx; + display: flex; + align-items: center; + justify-content: center; + width: 32rpx; + height: 32rpx; +} + +.requirement-submit__attachment-remove-icon { + width: 32rpx; + height: 32rpx; +} + +.requirement-submit__attachment-add { + display: flex; + flex-direction: column; + align-items: center; + justify-content: center; + width: 120rpx; + height: 120rpx; + background: #f8f9fb; + border: 1rpx dashed #d8dde6; + border-radius: 12rpx; +} + +.requirement-submit__attachment-add-icon { + font-size: 40rpx; + line-height: 1; + color: $color-text-secondary; +} + +.requirement-submit__attachment-add-text { + margin-top: 8rpx; + font-size: 20rpx; + color: $color-text-secondary; +} + +.requirement-submit__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; +} + +.requirement-submit__footer-btn { + display: flex; + flex: 1; + align-items: center; + justify-content: center; + height: 80rpx; + font-size: 28rpx; + border-radius: 12rpx; + + &--outline { + color: $color-primary; + background: $color-primary-light; + } + + &--primary { + font-weight: 600; + color: #ffffff; + background: $color-primary; + } +} diff --git a/src/pages/home-index/requirement-submit/index.vue b/src/pages/home-index/requirement-submit/index.vue index 4b836f8..7d2568e 100644 --- a/src/pages/home-index/requirement-submit/index.vue +++ b/src/pages/home-index/requirement-submit/index.vue @@ -350,357 +350,5 @@ function handleSubmit() { diff --git a/src/pages/index.scss b/src/pages/index.scss new file mode 100644 index 0000000..e69ae43 --- /dev/null +++ b/src/pages/index.scss @@ -0,0 +1,4 @@ +.root-container { + padding: 5rem 2.5rem; + text-align: center; +} diff --git a/src/pages/index.vue b/src/pages/index.vue index 553811e..834e10c 100644 --- a/src/pages/index.vue +++ b/src/pages/index.vue @@ -12,9 +12,6 @@ import InputEntry from '@/components/InputEntry.vue' - diff --git a/src/pages/message-center/components/MessageItem.scss b/src/pages/message-center/components/MessageItem.scss new file mode 100644 index 0000000..4b074f7 --- /dev/null +++ b/src/pages/message-center/components/MessageItem.scss @@ -0,0 +1,63 @@ +@import '@/styles/variables.scss'; + +.message-item { + display: flex; + align-items: flex-start; + width: 100%; + box-sizing: border-box; + padding: 24rpx 32rpx; + background: $color-bg-page; + + &:last-child { + border-bottom: none; + } +} + +.message-item__icon-wrap { + flex-shrink: 0; + margin-right: 24rpx; +} + +.message-item__icon { + width: 88rpx; + height: 88rpx; +} + +.message-item__content { + flex: 1; + min-width: 0; + padding-top: 4rpx; +} + +.message-item__row { + display: flex; + align-items: center; + justify-content: space-between; +} + +.message-item__title { + font-size: 30rpx; + font-weight: 600; + color: $color-text-primary; +} + +.message-item__time { + flex-shrink: 0; + margin-left: 16rpx; + font-size: 24rpx; + color: $color-text-secondary; +} + +.message-item__preview { + margin-top: 8rpx; + min-height: 78rpx; + font-size: 26rpx; + line-height: 1.5; + color: $color-text-secondary; + overflow: hidden; + text-overflow: ellipsis; + display: -webkit-box; + -webkit-line-clamp: 2; + line-clamp: 2; + -webkit-box-orient: vertical; +} diff --git a/src/pages/message-center/components/MessageItem.vue b/src/pages/message-center/components/MessageItem.vue index 412b1d6..8814e63 100644 --- a/src/pages/message-center/components/MessageItem.vue +++ b/src/pages/message-center/components/MessageItem.vue @@ -40,67 +40,5 @@ const emit = defineEmits<{ diff --git a/src/pages/message-center/customer-service/components/ChatMessage.scss b/src/pages/message-center/customer-service/components/ChatMessage.scss new file mode 100644 index 0000000..13c1101 --- /dev/null +++ b/src/pages/message-center/customer-service/components/ChatMessage.scss @@ -0,0 +1,75 @@ +@import '@/styles/variables.scss'; + +.chat-message { + display: flex; + align-items: flex-start; + margin-bottom: 32rpx; + + &--user { + flex-direction: row-reverse; + + .chat-message__body { + align-items: flex-end; + } + + .chat-message__nickname { + text-align: right; + } + } + + &--service { + flex-direction: row; + + .chat-message__body { + align-items: flex-start; + } + } +} + +.chat-message__avatar { + flex-shrink: 0; + width: 72rpx; + height: 72rpx; + border-radius: 50%; + background: #fff7e6; +} + +.chat-message__body { + display: flex; + flex-direction: column; + max-width: calc(100% - 96rpx); + margin: 0 16rpx; +} + +.chat-message__nickname { + margin-bottom: 8rpx; + font-size: 22rpx; + color: $color-text-secondary; +} + +.chat-message__bubble { + padding: 20rpx 24rpx; + border-radius: 16rpx; + + &--user { + background: $color-primary; + } + + &--service { + background: #f2f3f5; + } +} + +.chat-message__text { + font-size: 28rpx; + line-height: 1.5; + word-break: break-all; + + .chat-message__bubble--user & { + color: #ffffff; + } + + .chat-message__bubble--service & { + color: $color-text-primary; + } +} diff --git a/src/pages/message-center/customer-service/components/ChatMessage.vue b/src/pages/message-center/customer-service/components/ChatMessage.vue index a7deba4..2f23fd0 100644 --- a/src/pages/message-center/customer-service/components/ChatMessage.vue +++ b/src/pages/message-center/customer-service/components/ChatMessage.vue @@ -34,79 +34,5 @@ defineProps<{ diff --git a/src/pages/message-center/customer-service/index.scss b/src/pages/message-center/customer-service/index.scss new file mode 100644 index 0000000..4b37cdd --- /dev/null +++ b/src/pages/message-center/customer-service/index.scss @@ -0,0 +1,129 @@ +@import '@/styles/variables.scss'; + +.customer-service { + display: flex; + flex-direction: column; + height: 100vh; + overflow: hidden; + background: $color-bg-page; +} + +.customer-service__navbar { + display: flex; + align-items: center; + justify-content: space-between; + flex-shrink: 0; + padding: calc(var(--status-bar-height, 44px) + 12rpx) 24rpx 20rpx; + background: $color-bg-page; + border-bottom: 1rpx solid #f0f0f0; +} + +.customer-service__back { + display: flex; + align-items: center; + justify-content: center; + width: 64rpx; + height: 64rpx; +} + +.customer-service__back-icon { + width: 40rpx; + height: 40rpx; +} + +.customer-service__title { + font-size: 34rpx; + font-weight: 600; + color: $color-text-primary; +} + +.customer-service__navbar-placeholder { + width: 64rpx; + height: 64rpx; +} + +.customer-service__scroll { + flex: 1; + min-height: 0; + background: $color-bg-page; +} + +.customer-service__messages { + padding: 24rpx 24rpx 32rpx; +} + +.customer-service__footer { + flex-shrink: 0; + padding: 16rpx 24rpx calc(16rpx + env(safe-area-inset-bottom)); + background: $color-bg-page; + border-top: 1rpx solid #f0f0f0; +} + +.customer-service__input-row { + display: flex; + align-items: center; + gap: 16rpx; +} + +.customer-service__tool-btn { + display: flex; + flex-shrink: 0; + align-items: center; + justify-content: center; + width: 64rpx; + height: 64rpx; +} + +.customer-service__tool-icon { + width: 48rpx; + height: 48rpx; +} + +.customer-service__input { + flex: 1; + height: 72rpx; + padding: 0 24rpx; + font-size: 28rpx; + color: $color-text-primary; + background: #f2f3f5; + border-radius: 36rpx; +} + +.customer-service__placeholder { + color: $color-text-placeholder; +} + +.customer-service__panel { + display: flex; + align-items: flex-start; + justify-content: space-around; + min-height: 400rpx; + margin-top: 24rpx; + padding: 40rpx 24rpx 48rpx; + border-top: 1rpx solid #f0f0f0; +} + +.customer-service__panel-item { + display: flex; + flex-direction: column; + align-items: center; +} + +.customer-service__panel-icon-wrap { + display: flex; + align-items: center; + justify-content: center; + width: 112rpx; + height: 112rpx; +} + +.customer-service__panel-icon { + width: 112rpx; + height: 112rpx; +} + +.customer-service__panel-label { + margin-top: 12rpx; + font-size: 24rpx; + color: $color-text-secondary; +} diff --git a/src/pages/message-center/customer-service/index.vue b/src/pages/message-center/customer-service/index.vue index 18d95b3..9ba7714 100644 --- a/src/pages/message-center/customer-service/index.vue +++ b/src/pages/message-center/customer-service/index.vue @@ -167,133 +167,5 @@ function handleAttachment(type: 'camera' | 'photo' | 'file') { diff --git a/src/pages/message-center/index.scss b/src/pages/message-center/index.scss new file mode 100644 index 0000000..04fdc6a --- /dev/null +++ b/src/pages/message-center/index.scss @@ -0,0 +1,43 @@ +@import '@/styles/variables.scss'; + +.message-center { + display: flex; + flex-direction: column; + height: 100vh; + overflow: hidden; + background: $color-bg-page; +} + +.message-center__header { + position: relative; + display: flex; + align-items: center; + justify-content: center; + flex-shrink: 0; + padding: calc(var(--status-bar-height, 44px) + 60rpx) 32rpx 28rpx; + background: $color-bg-page; +} + +.message-center__title { + font-size: 36rpx; + font-weight: 600; + color: $color-text-primary; +} + +.message-center__read-all { + position: absolute; + right: 32rpx; + bottom: 28rpx; + font-size: 26rpx; + color: $color-text-secondary; +} + +.message-center__scroll { + flex: 1; + min-height: 0; +} + +.message-center__list { + width: 100%; + padding-bottom: calc(140rpx + env(safe-area-inset-bottom)); +} diff --git a/src/pages/message-center/index.vue b/src/pages/message-center/index.vue index 1a00305..b4dfcf6 100644 --- a/src/pages/message-center/index.vue +++ b/src/pages/message-center/index.vue @@ -76,47 +76,5 @@ function handleMessageTap(item: MessageItem) { diff --git a/src/pages/message-center/status-notification/components/StatusNotificationItem.scss b/src/pages/message-center/status-notification/components/StatusNotificationItem.scss new file mode 100644 index 0000000..1525db0 --- /dev/null +++ b/src/pages/message-center/status-notification/components/StatusNotificationItem.scss @@ -0,0 +1,61 @@ +@import '@/styles/variables.scss'; + +.status-notification-item { + display: flex; + align-items: flex-start; + width: 100%; + box-sizing: border-box; + padding: 24rpx 32rpx; + background: $color-bg-page; + border-bottom: 1rpx solid #f0f0f0; + + &:last-child { + border-bottom: none; + } +} + +.status-notification-item__icon { + flex-shrink: 0; + width: 88rpx; + height: 88rpx; + margin-right: 24rpx; +} + +.status-notification-item__content { + flex: 1; + min-width: 0; + padding-top: 4rpx; +} + +.status-notification-item__row { + display: flex; + align-items: center; + justify-content: space-between; +} + +.status-notification-item__title { + font-size: 30rpx; + font-weight: 600; + color: $color-text-primary; +} + +.status-notification-item__time { + flex-shrink: 0; + margin-left: 16rpx; + font-size: 24rpx; + color: $color-text-secondary; +} + +.status-notification-item__preview { + margin-top: 8rpx; + min-height: 78rpx; + font-size: 26rpx; + line-height: 1.5; + color: $color-text-secondary; + overflow: hidden; + text-overflow: ellipsis; + display: -webkit-box; + -webkit-line-clamp: 2; + line-clamp: 2; + -webkit-box-orient: vertical; +} diff --git a/src/pages/message-center/status-notification/components/StatusNotificationItem.vue b/src/pages/message-center/status-notification/components/StatusNotificationItem.vue index 007be45..bc4beaa 100644 --- a/src/pages/message-center/status-notification/components/StatusNotificationItem.vue +++ b/src/pages/message-center/status-notification/components/StatusNotificationItem.vue @@ -32,65 +32,5 @@ defineProps<{ diff --git a/src/pages/message-center/status-notification/index.scss b/src/pages/message-center/status-notification/index.scss new file mode 100644 index 0000000..e63ad40 --- /dev/null +++ b/src/pages/message-center/status-notification/index.scss @@ -0,0 +1,87 @@ +@import '@/styles/variables.scss'; + +.status-notification { + display: flex; + flex-direction: column; + height: 100vh; + overflow: hidden; + background: $color-bg-page; +} + +.status-notification__header { + position: relative; + display: flex; + align-items: center; + justify-content: center; + flex-shrink: 0; + padding: calc(var(--status-bar-height, 44px) + 60rpx) 32rpx 28rpx; + background: $color-bg-page; +} + +.status-notification__back { + position: absolute; + left: 32rpx; + bottom: 28rpx; + display: flex; + align-items: center; + justify-content: center; + width: 64rpx; + height: 64rpx; +} + +.status-notification__back-icon { + width: 40rpx; + height: 40rpx; +} + +.status-notification__title { + font-size: 36rpx; + font-weight: 600; + color: $color-text-primary; +} + +.status-notification__read-all { + position: absolute; + right: 32rpx; + bottom: 28rpx; + font-size: 26rpx; + color: $color-text-secondary; +} + +.status-notification__search { + display: flex; + align-items: center; + flex-shrink: 0; + height: 72rpx; + margin: 0 32rpx 16rpx; + padding: 0 24rpx; + background: $color-bg-section; + border-radius: 36rpx; +} + +.status-notification__search-icon { + flex-shrink: 0; + width: 32rpx; + height: 32rpx; + margin-right: 12rpx; +} + +.status-notification__search-input { + flex: 1; + font-size: 26rpx; + color: $color-text-primary; +} + +.status-notification__search-placeholder { + color: $color-text-placeholder; +} + +.status-notification__scroll { + flex: 1; + min-height: 0; +} + +.status-notification__list { + width: 100%; + padding-bottom: env(safe-area-inset-bottom); +} diff --git a/src/pages/message-center/status-notification/index.vue b/src/pages/message-center/status-notification/index.vue index 280d618..a7a851a 100644 --- a/src/pages/message-center/status-notification/index.vue +++ b/src/pages/message-center/status-notification/index.vue @@ -92,91 +92,5 @@ function handleReadAll() { diff --git a/src/pages/message-center/system-notification/index.scss b/src/pages/message-center/system-notification/index.scss new file mode 100644 index 0000000..f471e4e --- /dev/null +++ b/src/pages/message-center/system-notification/index.scss @@ -0,0 +1,87 @@ +@import '@/styles/variables.scss'; + +.system-notification { + display: flex; + flex-direction: column; + height: 100vh; + overflow: hidden; + background: $color-bg-page; +} + +.system-notification__header { + position: relative; + display: flex; + align-items: center; + justify-content: center; + flex-shrink: 0; + padding: calc(var(--status-bar-height, 44px) + 60rpx) 32rpx 28rpx; + background: $color-bg-page; +} + +.system-notification__back { + position: absolute; + left: 32rpx; + bottom: 28rpx; + display: flex; + align-items: center; + justify-content: center; + width: 64rpx; + height: 64rpx; +} + +.system-notification__back-icon { + width: 40rpx; + height: 40rpx; +} + +.system-notification__title { + font-size: 36rpx; + font-weight: 600; + color: $color-text-primary; +} + +.system-notification__read-all { + position: absolute; + right: 32rpx; + bottom: 28rpx; + font-size: 26rpx; + color: $color-text-secondary; +} + +.system-notification__search { + display: flex; + align-items: center; + flex-shrink: 0; + height: 72rpx; + margin: 0 32rpx 16rpx; + padding: 0 24rpx; + background: $color-bg-section; + border-radius: 36rpx; +} + +.system-notification__search-icon { + flex-shrink: 0; + width: 32rpx; + height: 32rpx; + margin-right: 12rpx; +} + +.system-notification__search-input { + flex: 1; + font-size: 26rpx; + color: $color-text-primary; +} + +.system-notification__search-placeholder { + color: $color-text-placeholder; +} + +.system-notification__scroll { + flex: 1; + min-height: 0; +} + +.system-notification__list { + width: 100%; + padding-bottom: env(safe-area-inset-bottom); +} diff --git a/src/pages/message-center/system-notification/index.vue b/src/pages/message-center/system-notification/index.vue index 93a3860..e6c9d3a 100644 --- a/src/pages/message-center/system-notification/index.vue +++ b/src/pages/message-center/system-notification/index.vue @@ -92,91 +92,5 @@ function handleReadAll() { diff --git a/src/pages/personal-center/index.scss b/src/pages/personal-center/index.scss new file mode 100644 index 0000000..d149875 --- /dev/null +++ b/src/pages/personal-center/index.scss @@ -0,0 +1,93 @@ +@import '@/styles/variables.scss'; + +.personal-center { + display: flex; + flex-direction: column; + height: 100vh; + overflow: hidden; + background: $color-bg-section; +} + +.personal-center__header { + display: flex; + flex-shrink: 0; + align-items: center; + padding: calc(var(--status-bar-height, 44px) + 48rpx) 32rpx 40rpx; +} + +.personal-center__avatar { + flex-shrink: 0; + width: 120rpx; + height: 120rpx; + border-radius: 50%; + background: $color-bg-page; +} + +.personal-center__profile { + flex: 1; + min-width: 0; + margin-left: 24rpx; +} + +.personal-center__nickname-row { + display: flex; + align-items: center; +} + +.personal-center__nickname { + font-size: 34rpx; + font-weight: 600; + color: $color-text-primary; +} + +.personal-center__edit-icon { + width: 28rpx; + height: 28rpx; + margin-left: 12rpx; +} + +.personal-center__phone { + display: block; + margin-top: 12rpx; + font-size: 28rpx; + color: $color-text-secondary; +} + +.personal-center__scroll { + flex: 1; + min-height: 0; +} + +.personal-center__menu-card { + margin: 0 24rpx; + padding: 8rpx 0 calc(140rpx + env(safe-area-inset-bottom)); + background: $color-bg-page; + border-radius: 20rpx; +} + +.personal-center__menu-item { + display: flex; + align-items: center; + min-height: 96rpx; + padding: 0 28rpx; +} + +.personal-center__menu-icon { + flex-shrink: 0; + width: 40rpx; + height: 40rpx; +} + +.personal-center__menu-label { + flex: 1; + margin-left: 20rpx; + font-size: 30rpx; + color: $color-text-primary; +} + +.personal-center__menu-arrow { + flex-shrink: 0; + font-size: 36rpx; + line-height: 1; + color: $color-text-placeholder; +} diff --git a/src/pages/personal-center/index.vue b/src/pages/personal-center/index.vue index 484e593..170d302 100644 --- a/src/pages/personal-center/index.vue +++ b/src/pages/personal-center/index.vue @@ -1,41 +1,99 @@ diff --git a/src/pages/project-center/after-sales-apply/index.scss b/src/pages/project-center/after-sales-apply/index.scss new file mode 100644 index 0000000..07f5abf --- /dev/null +++ b/src/pages/project-center/after-sales-apply/index.scss @@ -0,0 +1,328 @@ +@import '@/styles/variables.scss'; + +.after-sales-apply { + display: flex; + flex-direction: column; + min-height: 100vh; + background: $color-bg-section; +} + +.after-sales-apply__navbar { + position: relative; + z-index: 30; + display: flex; + align-items: center; + justify-content: space-between; + flex-shrink: 0; + padding: calc(var(--status-bar-height, 44px) + 12rpx) 24rpx 12rpx; + background: $color-bg-page; +} + +.after-sales-apply__back { + display: flex; + align-items: center; + justify-content: center; + width: 64rpx; + height: 64rpx; +} + +.after-sales-apply__back-icon { + width: 40rpx; + height: 40rpx; +} + +.after-sales-apply__navbar-title { + font-size: 34rpx; + font-weight: 600; + color: $color-text-primary; +} + +.after-sales-apply__navbar-placeholder { + width: 64rpx; + height: 64rpx; +} + +.after-sales-apply__scroll { + flex: 1; + height: 0; + padding: 20rpx 24rpx; + box-sizing: border-box; +} + +.after-sales-apply__card { + padding: 28rpx 24rpx; + margin-bottom: 20rpx; + background: $color-bg-page; + border-radius: 20rpx; + + &--dropdown { + position: relative; + z-index: 20; + overflow: visible; + } +} + +.after-sales-apply__field { + margin-bottom: 28rpx; + + &:last-child { + margin-bottom: 0; + } +} + +.after-sales-apply__label-row { + display: flex; + align-items: center; + justify-content: space-between; + margin-bottom: 16rpx; +} + +.after-sales-apply__label { + display: block; + margin-bottom: 16rpx; + font-size: 28rpx; + font-weight: 500; + color: $color-text-primary; + + &--inline { + display: inline; + margin-bottom: 0; + } +} + +.after-sales-apply__required { + color: #ff4d4f; +} + +.after-sales-apply__hint { + font-size: 24rpx; + color: $color-text-secondary; +} + +.after-sales-apply__input { + width: 100%; + font-size: 28rpx; + color: $color-text-primary; + + &--box { + height: 80rpx; + padding: 0 24rpx; + background: $color-bg-page; + border: 1rpx solid #e8eaef; + border-radius: 12rpx; + box-sizing: border-box; + } +} + +.after-sales-apply__placeholder { + color: $color-text-placeholder; +} + +.after-sales-apply__select-wrap { + position: relative; + z-index: 20; +} + +.after-sales-apply__select { + display: flex; + align-items: center; + height: 80rpx; + padding: 0 24rpx; + background: $color-bg-page; + border: 1rpx solid #e8eaef; + border-radius: 12rpx; +} + +.after-sales-apply__select-text { + flex: 1; + font-size: 28rpx; + color: $color-text-primary; + + &--placeholder { + color: $color-text-placeholder; + } +} + +.after-sales-apply__select-arrow { + flex-shrink: 0; + margin-left: 12rpx; + font-size: 24rpx; + color: $color-text-secondary; + transition: transform 0.2s ease; + + &--open { + transform: rotate(180deg); + } +} + +.after-sales-apply__dropdown { + position: absolute; + top: calc(100% + 8rpx); + right: 0; + left: 0; + z-index: 21; + overflow: hidden; + background: $color-bg-page; + border: 1rpx solid #e8eaef; + border-radius: 12rpx; + box-shadow: 0 8rpx 24rpx rgba(0, 0, 0, 0.08); +} + +.after-sales-apply__dropdown-item { + padding: 24rpx; + font-size: 28rpx; + color: $color-text-primary; + border-bottom: 1rpx solid #f0f0f0; + + &:last-child { + border-bottom: none; + } + + &--active { + color: $color-primary; + background: $color-primary-light; + } +} + +.after-sales-apply__dropdown-mask { + position: fixed; + top: 0; + right: 0; + bottom: 0; + left: 0; + z-index: 10; + background: transparent; +} + +.after-sales-apply__textarea-wrap { + position: relative; + padding: 20rpx 24rpx 48rpx; + background: $color-bg-page; + border: 1rpx solid #e8eaef; + border-radius: 12rpx; +} + +.after-sales-apply__textarea { + width: 100%; + min-height: 180rpx; + font-size: 28rpx; + line-height: 1.6; + color: $color-text-primary; + + &--remark { + min-height: 140rpx; + padding: 20rpx 24rpx; + background: $color-bg-page; + border: 1rpx solid #e8eaef; + border-radius: 12rpx; + box-sizing: border-box; + } +} + +.after-sales-apply__counter { + position: absolute; + right: 24rpx; + bottom: 16rpx; + font-size: 22rpx; + color: $color-text-secondary; +} + +.after-sales-apply__attachment-row { + display: flex; + flex-wrap: wrap; + gap: 20rpx; + padding: 10rpx 10rpx 0 0; +} + +.after-sales-apply__attachment-item { + position: relative; + display: flex; + flex-direction: column; + align-items: center; + width: 160rpx; + padding: 20rpx 16rpx; + background: $color-bg-section; + border-radius: 12rpx; +} + +.after-sales-apply__attachment-remove { + position: absolute; + top: -10rpx; + right: -10rpx; + width: 32rpx; + height: 32rpx; +} + +.after-sales-apply__attachment-remove-icon { + width: 32rpx; + height: 32rpx; +} + +.after-sales-apply__attachment-icon { + width: 64rpx; + height: 64rpx; +} + +.after-sales-apply__attachment-name { + margin-top: 12rpx; + font-size: 22rpx; + color: $color-text-primary; + text-align: center; + word-break: break-all; +} + +.after-sales-apply__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; +} + +.after-sales-apply__attachment-add-icon { + font-size: 40rpx; + line-height: 1; + color: $color-text-secondary; +} + +.after-sales-apply__attachment-add-text { + margin-top: 8rpx; + font-size: 20rpx; + color: $color-text-secondary; +} + +.after-sales-apply__footer { + display: flex; + gap: 20rpx; + flex-shrink: 0; + padding: 16rpx 24rpx calc(16rpx + env(safe-area-inset-bottom)); + background: $color-bg-page; + border-top: 1rpx solid #f0f0f0; +} + +.after-sales-apply__footer-btn { + display: flex; + align-items: center; + justify-content: center; + height: 88rpx; + font-size: 30rpx; + border-radius: 12rpx; + + &--outline { + flex: 0.8; + color: $color-primary; + background: $color-bg-page; + border: 1rpx solid $color-primary; + } + + &--primary { + flex: 1.2; + font-weight: 600; + color: #ffffff; + background: $color-primary; + } +} diff --git a/src/pages/project-center/after-sales-apply/index.vue b/src/pages/project-center/after-sales-apply/index.vue new file mode 100644 index 0000000..6fdb44a --- /dev/null +++ b/src/pages/project-center/after-sales-apply/index.vue @@ -0,0 +1,316 @@ + + +