refactor(frontend): 统一使用wd-text组件替换原生text标签,优化页面配置

1.  全局替换普通text标签为wd-text组件,统一文本样式与功能
2.  调整页面全局配置与tabBar配置,按平台动态裁剪无效配置
3.  修复微信小程序端表单item样式兼容问题,添加自定义样式隐藏空left区域
4.  移除登录页冗余的微信一键登录相关代码
This commit is contained in:
zhangtao
2026-08-11 00:49:00 +08:00
parent 50eac1872b
commit 7bbc489c59
21 changed files with 475 additions and 277 deletions
+9 -8
View File
@@ -9,6 +9,11 @@
*/ */
import { defineUniPages } from '@uni-helper/vite-plugin-uni-pages' import { defineUniPages } from '@uni-helper/vite-plugin-uni-pages'
// 按构建平台动态裁剪配置(vite-plugin-uni-pages 不处理条件编译注释,用 JS 逻辑)
const UNI_PLATFORM = process.env.UNI_PLATFORM || ''
const isWeixin = UNI_PLATFORM === 'mp-weixin'
const isAlipay = UNI_PLATFORM === 'mp-alipay'
export default defineUniPages({ export default defineUniPages({
pages: [], pages: [],
globalStyle: { globalStyle: {
@@ -27,17 +32,13 @@ export default defineUniPages({
enablePullDownRefresh: false, enablePullDownRefresh: false,
onReachBottomDistance: 50, onReachBottomDistance: 50,
// 动画配置 // 页面切换动画(微信小程序 window 不支持 animationType/animationDuration,构建时排除)
animationType: 'pop-in', ...(isWeixin ? {} : { animationType: 'pop-in', animationDuration: 300 }),
animationDuration: 300,
}, },
tabBar: { tabBar: {
custom: true, custom: true,
// #ifdef MP-ALIPAY // customize/overlay 为支付宝小程序 tabBar 配置(微信端编译进 app.json 会告警,按平台裁剪)
customize: true, ...(isAlipay ? { customize: true, overlay: true } : {}),
// 暂时不生效。4.71.2025061206-alpha已修复:https://uniapp.dcloud.net.cn/release-note-alpha.html#_4-71-2025061206-alpha,我们等正式版发布后更新。
overlay: true,
// #endif
height: '0', height: '0',
color: '@tabColor', color: '@tabColor',
selectedColor: '@tabSelectedColor', selectedColor: '@tabSelectedColor',
+1
View File
@@ -66,6 +66,7 @@ declare module 'vue' {
WdTabbarItem: typeof import('@wot-ui/ui/components/wd-tabbar-item/wd-tabbar-item.vue')['default'] WdTabbarItem: typeof import('@wot-ui/ui/components/wd-tabbar-item/wd-tabbar-item.vue')['default']
WdTabs: typeof import('@wot-ui/ui/components/wd-tabs/wd-tabs.vue')['default'] WdTabs: typeof import('@wot-ui/ui/components/wd-tabs/wd-tabs.vue')['default']
WdTag: typeof import('@wot-ui/ui/components/wd-tag/wd-tag.vue')['default'] WdTag: typeof import('@wot-ui/ui/components/wd-tag/wd-tag.vue')['default']
WdText: typeof import('@wot-ui/ui/components/wd-text/wd-text.vue')['default']
WdTextarea: typeof import('@wot-ui/ui/components/wd-textarea/wd-textarea.vue')['default'] WdTextarea: typeof import('@wot-ui/ui/components/wd-textarea/wd-textarea.vue')['default']
WdToast: typeof import('@wot-ui/ui/components/wd-toast/wd-toast.vue')['default'] WdToast: typeof import('@wot-ui/ui/components/wd-toast/wd-toast.vue')['default']
WdUpload: typeof import('@wot-ui/ui/components/wd-upload/wd-upload.vue')['default'] WdUpload: typeof import('@wot-ui/ui/components/wd-upload/wd-upload.vue')['default']
+12 -8
View File
@@ -99,11 +99,9 @@ export default {
</view> </view>
</view> </view>
<view class="wd-privacy-popup__container"> <view class="wd-privacy-popup__container">
<text>{{ desc }}</text> <wd-text :text="desc" />
<text class="wd-privacy-popup__container-protocol" @click="openPrivacyContract"> <wd-text class="wd-privacy-popup__container-protocol" @click="openPrivacyContract" :text="protocol" />
{{ protocol }} <wd-text :text="subDesc" />
</text>
<text>{{ subDesc }}</text>
</view> </view>
<view class="wd-privacy-popup__footer"> <view class="wd-privacy-popup__footer">
<button id="disagree-btn" class="is-block is-round is-medium is-plain wd-privacy-popup__footer-disagree wd-button" @click="handleDisagree"> <button id="disagree-btn" class="is-block is-round is-medium is-plain wd-privacy-popup__footer-disagree wd-button" @click="handleDisagree">
@@ -122,15 +120,19 @@ export default {
</view> </view>
</template> </template>
<style lang="scss" scoped> <style lang="scss">
:deep(.wd-privacy-popup) { // 非 scoped:wd-popup 通过 custom-class 传入根类名,弹窗挂载层级不受组件作用域约束,
// :deep() 在小程序端对 virtualHost 组件不可靠,改用全局类名直接命中(H5/MP 均生效)
.wd-privacy-popup {
width: 600rpx; width: 600rpx;
padding: 0 24rpx; padding: 0 24rpx;
box-sizing: border-box; box-sizing: border-box;
border-radius: 32rpx; border-radius: 32rpx;
overflow: hidden; overflow: hidden;
} }
</style>
<style lang="scss" scoped>
.wd-privacy-popup { .wd-privacy-popup {
&__header { &__header {
width: 100%; width: 100%;
@@ -163,7 +165,9 @@ export default {
justify-content: space-between; justify-content: space-between;
padding-bottom: 36rpx; padding-bottom: 36rpx;
button { /* 组件 wxss 不允许标签选择器(微信小程序限制),改用类选择器 */
&-disagree,
&-agree {
border: none; border: none;
outline: none; outline: none;
} }
+1 -5
View File
@@ -8,9 +8,7 @@
"backgroundColorTop": "@bgColorTop", "backgroundColorTop": "@bgColorTop",
"backgroundColorBottom": "@bgColorBottom", "backgroundColorBottom": "@bgColorBottom",
"enablePullDownRefresh": false, "enablePullDownRefresh": false,
"onReachBottomDistance": 50, "onReachBottomDistance": 50
"animationType": "pop-in",
"animationDuration": 300
}, },
"pages": [ "pages": [
// #ifdef APP // #ifdef APP
@@ -172,8 +170,6 @@
], ],
"tabBar": { "tabBar": {
"custom": true, "custom": true,
"customize": true,
"overlay": true,
"height": "0", "height": "0",
"color": "@tabColor", "color": "@tabColor",
"selectedColor": "@tabSelectedColor", "selectedColor": "@tabSelectedColor",
+7 -18
View File
@@ -330,6 +330,7 @@ function getGreeting() {
:interval="4500" :interval="4500"
:autoplay="true" :autoplay="true"
:loop="true" :loop="true"
:adjust-height="false"
> >
<template #default="{ index }"> <template #default="{ index }">
<view class="banner-slide" :class="banners[index].cls" @click="banners[index].onClick"> <view class="banner-slide" :class="banners[index].cls" @click="banners[index].onClick">
@@ -398,9 +399,7 @@ function getGreeting() {
<!-- 运营概览 --> <!-- 运营概览 -->
<view class="mb-2 mt-4 flex items-center gap-2 px-3"> <view class="mb-2 mt-4 flex items-center gap-2 px-3">
<view class="h-3.5 w-1 rounded-full" style="background-color: var(--primary-color, #4F8CFF);" /> <view class="h-3.5 w-1 rounded-full" style="background-color: var(--primary-color, #4F8CFF);" />
<text class="text-3.5 font-bold wot-text-text-main"> <wd-text class="text-3.5 wot-text-text-main" :text="t('index.opsOverview')" bold />
{{ t('index.opsOverview') }}
</text>
</view> </view>
<SkeletonPage v-if="loading && !dashboardStats" :rows="3" /> <SkeletonPage v-if="loading && !dashboardStats" :rows="3" />
<view v-else class="mx-3"> <view v-else class="mx-3">
@@ -454,17 +453,13 @@ function getGreeting() {
<view id="monitor-section" class="mt-4"> <view id="monitor-section" class="mt-4">
<view class="mb-2 flex items-center gap-2 px-3"> <view class="mb-2 flex items-center gap-2 px-3">
<view class="h-3.5 w-1 rounded-full" style="background-color: var(--danger-color, #EF4444);" /> <view class="h-3.5 w-1 rounded-full" style="background-color: var(--danger-color, #EF4444);" />
<text class="text-3.5 font-bold wot-text-text-main"> <wd-text class="text-3.5 wot-text-text-main" :text="t('index.sysMonitor')" bold />
{{ t('index.sysMonitor') }}
</text>
</view> </view>
<!-- 登录趋势折线图 --> <!-- 登录趋势折线图 -->
<view class="mx-3 mb-3 rounded-2 p-4 wot-bg-filled-oppo"> <view class="mx-3 mb-3 rounded-2 p-4 wot-bg-filled-oppo">
<view class="mb-4 flex items-center gap-2"> <view class="mb-4 flex items-center gap-2">
<text class="text-3.5 font-bold wot-text-text-main"> <wd-text class="text-3.5 wot-text-text-main" :text="t('index.loginTrend')" bold />
{{ t('index.loginTrend') }}
</text>
</view> </view>
<uni-echarts custom-class="h-52 w-full" :option="loginTrendOption" /> <uni-echarts custom-class="h-52 w-full" :option="loginTrendOption" />
</view> </view>
@@ -474,13 +469,9 @@ function getGreeting() {
<view v-if="recentNotices.length > 0" class="mb-2 mt-4 flex items-center justify-between px-3"> <view v-if="recentNotices.length > 0" class="mb-2 mt-4 flex items-center justify-between px-3">
<view class="flex items-center gap-2"> <view class="flex items-center gap-2">
<view class="h-3.5 w-1 rounded-full" style="background-color: var(--success-color, #10B981);" /> <view class="h-3.5 w-1 rounded-full" style="background-color: var(--success-color, #10B981);" />
<text class="text-3.5 font-bold wot-text-text-main"> <wd-text class="text-3.5 wot-text-text-main" :text="t('index.latestNotice')" bold />
{{ t('index.latestNotice') }}
</text>
</view> </view>
<text class="text-3 wot-text-primary" @click="navigateTo('work-notices')"> <wd-text class="text-3" :text="t('common.all')" type="primary" @click="navigateTo('work-notices')" />
{{ t('common.all') }}
</text>
</view> </view>
<view v-if="recentNotices.length > 0" class="mx-3"> <view v-if="recentNotices.length > 0" class="mx-3">
<wd-cell-group border custom-class="rounded-2! overflow-hidden"> <wd-cell-group border custom-class="rounded-2! overflow-hidden">
@@ -492,9 +483,7 @@ function getGreeting() {
@click="navigateTo('work-notices')" @click="navigateTo('work-notices')"
> >
<template #label> <template #label>
<text class="text-2.5 wot-text-text-auxiliary"> <wd-text class="text-2.5 wot-text-text-auxiliary" :text="item.created_time || ''" />
{{ item.created_time || '' }}
</text>
</template> </template>
</wd-cell> </wd-cell>
</wd-cell-group> </wd-cell-group>
+13 -6
View File
@@ -85,7 +85,7 @@ function goLogin() {
<view class="forget-form"> <view class="forget-form">
<wd-form ref="forgetFormRef" :model="forgetForm" :schema="forgetSchema"> <wd-form ref="forgetFormRef" :model="forgetForm" :schema="forgetSchema">
<wd-form-item prop="username"> <wd-form-item prop="username" custom-style="margin-bottom: 14rpx; padding-left: 0; padding-right: 0;">
<wd-input <wd-input
v-model="forgetForm.username" v-model="forgetForm.username"
:placeholder="t('common.form.usernamePlaceholder')" :placeholder="t('common.form.usernamePlaceholder')"
@@ -94,7 +94,7 @@ function goLogin() {
prefix-icon="user" prefix-icon="user"
/> />
</wd-form-item> </wd-form-item>
<wd-form-item prop="new_password"> <wd-form-item prop="new_password" custom-style="margin-bottom: 14rpx; padding-left: 0; padding-right: 0;">
<wd-input <wd-input
v-model="forgetForm.new_password" v-model="forgetForm.new_password"
:placeholder="t('common.form.newPasswordPlaceholder')" :placeholder="t('common.form.newPasswordPlaceholder')"
@@ -104,7 +104,7 @@ function goLogin() {
prefix-icon="lock" prefix-icon="lock"
/> />
</wd-form-item> </wd-form-item>
<wd-form-item prop="confirmPassword"> <wd-form-item prop="confirmPassword" custom-style="margin-bottom: 14rpx; padding-left: 0; padding-right: 0;">
<wd-input <wd-input
v-model="forgetForm.confirmPassword" v-model="forgetForm.confirmPassword"
:placeholder="t('common.form.confirmNewPlaceholder')" :placeholder="t('common.form.confirmNewPlaceholder')"
@@ -121,9 +121,7 @@ function goLogin() {
</view> </view>
<view class="forget-footer"> <view class="forget-footer">
<text class="forget-footer__link wot-text-primary" @click="goLogin"> <wd-text class="forget-footer__link" :text="t('forget.toLogin')" type="primary" @click="goLogin" />
{{ t('forget.toLogin') }}
</text>
</view> </view>
</view> </view>
</view> </view>
@@ -215,3 +213,12 @@ function goLogin() {
} }
} }
</style> </style>
<style lang="scss">
/* MP 端兼容:wd-form-item 内部 wd-cell 因 uni-app 插槽静态声明(u-s)误判 label/title 插槽被使用,
showLeft=true 渲染空 left 区域(flex:1 占半宽),H5 端运行时插槽判定无此问题。
本页 form-item 无 title/label/prefix 内容,隐藏 left 安全,保证输入框与登录按钮同宽 */
.forget-card .wd-form-item .wd-cell__left {
display: none;
}
</style>
+20 -96
View File
@@ -7,7 +7,6 @@ import { computed, nextTick, reactive, ref, watch } from 'vue'
import { useI18n } from 'vue-i18n' import { useI18n } from 'vue-i18n'
import AuthAPI from '@/api/module_system/auth' import AuthAPI from '@/api/module_system/auth'
import { useI18nNavTitle } from '@/composables/useI18nNavTitle' import { useI18nNavTitle } from '@/composables/useI18nNavTitle'
import { useWxLogin } from '@/composables/useWxLogin'
import { REMEMBER_ME_KEY } from '@/constants' import { REMEMBER_ME_KEY } from '@/constants'
import { useConfigStore } from '@/store/configStore' import { useConfigStore } from '@/store/configStore'
import { useUserStore } from '@/store/userStore' import { useUserStore } from '@/store/userStore'
@@ -22,7 +21,6 @@ const sliderCaptchaRef = ref<SlideVerifyInstance>()
const loading = ref(false) const loading = ref(false)
const userStore = useUserStore() const userStore = useUserStore()
const configStore = useConfigStore() const configStore = useConfigStore()
const { wxLogin, wxPhoneLogin } = useWxLogin()
const redirect = ref('/pages/index/index') const redirect = ref('/pages/index/index')
/** 规范化 BASE_URL(保证以 / 结尾),用于拼接静态资源路径:H5 下避免 base '/app' 拼出 /appstatic/xxx */ /** 规范化 BASE_URL(保证以 / 结尾),用于拼接静态资源路径:H5 下避免 base '/app' 拼出 /appstatic/xxx */
@@ -241,43 +239,6 @@ async function handleOAuth(provider: OAuthProvider) {
uni.showToast({ title: t('login.oauthFailed'), icon: 'none' }) uni.showToast({ title: t('login.oauthFailed'), icon: 'none' })
} }
} }
/** 微信一键登录(仅小程序端显示按钮) */
const wxLoading = ref(false)
async function handleWxLogin() {
if (wxLoading.value)
return
wxLoading.value = true
try {
await wxLogin()
uni.reLaunch({ url: redirect.value })
}
catch {
uni.showToast({ title: t('login.wxLoginFailed'), icon: 'none' })
}
finally {
wxLoading.value = false
}
}
/** 微信手机号登录(配合 open-type="getPhoneNumber") */
async function handleWxPhoneLogin(e: any) {
if (e.detail.errMsg !== 'getPhoneNumber:ok') {
uni.showToast({ title: t('login.phoneAuthCancel'), icon: 'none' })
return
}
wxLoading.value = true
try {
await wxPhoneLogin(e.detail.code)
uni.reLaunch({ url: redirect.value })
}
catch {
uni.showToast({ title: t('login.phoneLoginFailed'), icon: 'none' })
}
finally {
wxLoading.value = false
}
}
</script> </script>
<template> <template>
@@ -288,9 +249,7 @@ async function handleWxPhoneLogin(e: any) {
<text class="brand-title"> <text class="brand-title">
{{ brandTitle }} {{ brandTitle }}
</text> </text>
<text class="brand-subtitle"> <wd-text class="brand-subtitle" :text="brandSubtitle" />
{{ brandSubtitle }}
</text>
</view> </view>
<!-- Form card --> <!-- Form card -->
@@ -299,39 +258,9 @@ async function handleWxPhoneLogin(e: any) {
{{ t('login.cardTitle') }} {{ t('login.cardTitle') }}
</text> </text>
<!-- 微信一键登录(仅小程序端显示) -->
<!-- #ifdef MP-WEIXIN -->
<view class="wx-login-section">
<wd-button
type="primary"
:loading="wxLoading"
round
block
@click="handleWxLogin"
>
<wd-icon name="wechat" size="18px" color="#FFFFFF" />
<text class="ml-1">
{{ t('login.wxLogin') }}
</text>
</wd-button>
<wd-button
plain
round
block
custom-class="mt-3"
:loading="wxLoading"
open-type="getPhoneNumber"
@getphonenumber="handleWxPhoneLogin"
>
{{ t('login.phoneLogin') }}
</wd-button>
</view>
<wd-divider>{{ t('login.orAccount') }}</wd-divider>
<!-- #endif -->
<wd-form ref="loginFormRef" :model="loginFormData" :schema="loginSchema"> <wd-form ref="loginFormRef" :model="loginFormData" :schema="loginSchema">
<!-- Username — wot 原生 wd-input,前缀图标走 prefix-icon 属性 --> <!-- Username — wot 原生 wd-input,前缀图标走 prefix-icon 属性 -->
<wd-form-item prop="username"> <wd-form-item prop="username" custom-style="margin-bottom: 14rpx; padding-left: 0; padding-right: 0;">
<wd-input <wd-input
v-model="loginFormData.username" v-model="loginFormData.username"
:placeholder="t('common.form.usernamePlaceholder')" :placeholder="t('common.form.usernamePlaceholder')"
@@ -344,7 +273,7 @@ async function handleWxPhoneLogin(e: any) {
</wd-form-item> </wd-form-item>
<!-- Password — show-password 自动启用密码可见性切换 --> <!-- Password — show-password 自动启用密码可见性切换 -->
<wd-form-item prop="password"> <wd-form-item prop="password" custom-style="margin-bottom: 14rpx; padding-left: 0; padding-right: 0;">
<wd-input <wd-input
v-model="loginFormData.password" v-model="loginFormData.password"
:placeholder="t('common.form.passwordPlaceholder')" :placeholder="t('common.form.passwordPlaceholder')"
@@ -358,7 +287,7 @@ async function handleWxPhoneLogin(e: any) {
</wd-form-item> </wd-form-item>
<!-- Slider Captcha — wd-slide-verify 滑块拖动验证(条件显示) --> <!-- Slider Captcha — wd-slide-verify 滑块拖动验证(条件显示) -->
<wd-form-item v-if="captchaState.enable"> <wd-form-item v-if="captchaState.enable" custom-style="margin-bottom: 14rpx; padding-left: 0; padding-right: 0;">
<wd-slide-verify <wd-slide-verify
ref="sliderCaptchaRef" ref="sliderCaptchaRef"
:text="t('login.sliderText')" :text="t('login.sliderText')"
@@ -373,9 +302,7 @@ async function handleWxPhoneLogin(e: any) {
<wd-checkbox v-model="loginFormData.remember" size="18px"> <wd-checkbox v-model="loginFormData.remember" size="18px">
{{ t('login.remember') }} {{ t('login.remember') }}
</wd-checkbox> </wd-checkbox>
<text class="forgot-link wot-text-primary" @click="goForget"> <wd-text class="forgot-link" :text="t('login.forgot')" type="primary" @click="goForget" />
{{ t('login.forgot') }}
</text>
</view> </view>
<!-- Submit --> <!-- Submit -->
@@ -400,9 +327,7 @@ async function handleWxPhoneLogin(e: any) {
<view class="oauth-btn__icon" style="background: #07C160"> <view class="oauth-btn__icon" style="background: #07C160">
<image class="oauth-btn__iconify" src="/static/icons/wechat.svg" /> <image class="oauth-btn__iconify" src="/static/icons/wechat.svg" />
</view> </view>
<text class="oauth-btn__label"> <wd-text class="oauth-btn__label" :text="t('login.wechat')" />
{{ t('login.wechat') }}
</text>
</wd-grid-item> </wd-grid-item>
<!-- GitHub --> <!-- GitHub -->
@@ -410,9 +335,7 @@ async function handleWxPhoneLogin(e: any) {
<view class="oauth-btn__icon" style="background: #24292F"> <view class="oauth-btn__icon" style="background: #24292F">
<image class="oauth-btn__iconify" src="/static/icons/github.svg" /> <image class="oauth-btn__iconify" src="/static/icons/github.svg" />
</view> </view>
<text class="oauth-btn__label"> <wd-text class="oauth-btn__label" :text="t('login.github')" />
{{ t('login.github') }}
</text>
</wd-grid-item> </wd-grid-item>
<!-- Gitee --> <!-- Gitee -->
@@ -420,9 +343,7 @@ async function handleWxPhoneLogin(e: any) {
<view class="oauth-btn__icon" style="background: #C71D23"> <view class="oauth-btn__icon" style="background: #C71D23">
<image class="oauth-btn__iconify" src="/static/icons/gitee.svg" /> <image class="oauth-btn__iconify" src="/static/icons/gitee.svg" />
</view> </view>
<text class="oauth-btn__label"> <wd-text class="oauth-btn__label" :text="t('login.gitee')" />
{{ t('login.gitee') }}
</text>
</wd-grid-item> </wd-grid-item>
<!-- QQ --> <!-- QQ -->
@@ -430,21 +351,15 @@ async function handleWxPhoneLogin(e: any) {
<view class="oauth-btn__icon" style="background: #12B7F5"> <view class="oauth-btn__icon" style="background: #12B7F5">
<image class="oauth-btn__iconify" src="/static/icons/qq.svg" /> <image class="oauth-btn__iconify" src="/static/icons/qq.svg" />
</view> </view>
<text class="oauth-btn__label"> <wd-text class="oauth-btn__label" :text="t('login.qq')" />
{{ t('login.qq') }}
</text>
</wd-grid-item> </wd-grid-item>
</wd-grid> </wd-grid>
</view> </view>
<!-- Footer --> <!-- Footer -->
<view class="login-footer"> <view class="login-footer">
<text class="login-footer__text"> <wd-text class="login-footer__text" :text="t('login.noAccount')" />
{{ t('login.noAccount') }} <wd-text class="login-footer__link" :text="t('login.toRegister')" type="primary" @click="goRegister" />
</text>
<text class="login-footer__link wot-text-primary" @click="goRegister">
{{ t('login.toRegister') }}
</text>
</view> </view>
</view> </view>
</template> </template>
@@ -637,3 +552,12 @@ async function handleWxPhoneLogin(e: any) {
} }
} }
</style> </style>
<style lang="scss">
/* MP 端兼容:wd-form-item 内部 wd-cell 因 uni-app 插槽静态声明(u-s)误判 label/title 插槽被使用,
showLeft=true 渲染空 left 区域(flex:1 占半宽),H5 端运行时插槽判定无此问题。
本页 form-item 无 title/label/prefix 内容,隐藏 left 安全,保证输入框与登录按钮同宽 */
.login-card .wd-form-item .wd-cell__left {
display: none;
}
</style>
+16 -13
View File
@@ -148,7 +148,7 @@ function goLogin() {
<view class="register-form"> <view class="register-form">
<wd-form ref="registerFormRef" :model="registerForm" :schema="registerSchema"> <wd-form ref="registerFormRef" :model="registerForm" :schema="registerSchema">
<wd-form-item prop="username"> <wd-form-item prop="username" custom-style="margin-bottom: 14rpx; padding-left: 0; padding-right: 0;">
<wd-input <wd-input
v-model="registerForm.username" v-model="registerForm.username"
:placeholder="t('common.form.usernamePlaceholder')" :placeholder="t('common.form.usernamePlaceholder')"
@@ -157,7 +157,7 @@ function goLogin() {
prefix-icon="user" prefix-icon="user"
/> />
</wd-form-item> </wd-form-item>
<wd-form-item prop="name"> <wd-form-item prop="name" custom-style="margin-bottom: 14rpx; padding-left: 0; padding-right: 0;">
<wd-input <wd-input
v-model="registerForm.name" v-model="registerForm.name"
:placeholder="t('common.form.nicknamePlaceholder')" :placeholder="t('common.form.nicknamePlaceholder')"
@@ -166,7 +166,7 @@ function goLogin() {
prefix-icon="user" prefix-icon="user"
/> />
</wd-form-item> </wd-form-item>
<wd-form-item prop="password"> <wd-form-item prop="password" custom-style="margin-bottom: 14rpx; padding-left: 0; padding-right: 0;">
<wd-input <wd-input
v-model="registerForm.password" v-model="registerForm.password"
:placeholder="t('common.form.passwordPlaceholder')" :placeholder="t('common.form.passwordPlaceholder')"
@@ -176,7 +176,7 @@ function goLogin() {
prefix-icon="lock" prefix-icon="lock"
/> />
</wd-form-item> </wd-form-item>
<wd-form-item prop="confirmPassword"> <wd-form-item prop="confirmPassword" custom-style="margin-bottom: 14rpx; padding-left: 0; padding-right: 0;">
<wd-input <wd-input
v-model="registerForm.confirmPassword" v-model="registerForm.confirmPassword"
:placeholder="t('common.form.confirmPlaceholder')" :placeholder="t('common.form.confirmPlaceholder')"
@@ -193,9 +193,7 @@ function goLogin() {
<wd-checkbox v-model="agreeRead" size="18px"> <wd-checkbox v-model="agreeRead" size="18px">
{{ t('register.agree') }} {{ t('register.agree') }}
</wd-checkbox> </wd-checkbox>
<text class="register-agreement__link wot-text-primary" @click="handleAgreementOpen"> <wd-text class="register-agreement__link" :text="t('register.userAgreement')" type="primary" @click="handleAgreementOpen" />
{{ t('register.userAgreement') }}
</text>
</view> </view>
<wd-button type="primary" round block :loading="submitting" @click="handleSubmit"> <wd-button type="primary" round block :loading="submitting" @click="handleSubmit">
@@ -204,12 +202,8 @@ function goLogin() {
</view> </view>
<view class="register-footer"> <view class="register-footer">
<text class="register-footer__text"> <wd-text class="register-footer__text" :text="t('register.hasAccount')" />
{{ t('register.hasAccount') }} <wd-text class="register-footer__link" :text="t('register.toLogin')" type="primary" @click="goLogin" />
</text>
<text class="register-footer__link wot-text-primary" @click="goLogin">
{{ t('register.toLogin') }}
</text>
</view> </view>
</view> </view>
</view> </view>
@@ -323,3 +317,12 @@ function goLogin() {
} }
} }
</style> </style>
<style lang="scss">
/* MP 端兼容:wd-form-item 内部 wd-cell 因 uni-app 插槽静态声明(u-s)误判 label/title 插槽被使用,
showLeft=true 渲染空 left 区域(flex:1 占半宽),H5 端运行时插槽判定无此问题。
本页 form-item 无 title/label/prefix 内容,隐藏 left 安全,保证输入框与登录按钮同宽 */
.register-card .wd-form-item .wd-cell__left {
display: none;
}
</style>
+1 -3
View File
@@ -231,9 +231,7 @@ async function handleSubmitPassword() {
<view class="mx-3 mb-3"> <view class="mx-3 mb-3">
<view class="mb-2 mt-1 flex items-center gap-2 px-3"> <view class="mb-2 mt-1 flex items-center gap-2 px-3">
<view class="h-3.5 w-1 rounded-full" style="background-color: var(--primary-color, #4F8CFF);" /> <view class="h-3.5 w-1 rounded-full" style="background-color: var(--primary-color, #4F8CFF);" />
<text class="text-3.5 font-bold wot-text-text-main"> <wd-text class="text-3.5 wot-text-text-main" :text="t('common.settings')" bold />
{{ t('common.settings') }}
</text>
</view> </view>
<wd-cell-group border custom-class="rounded-2! overflow-hidden"> <wd-cell-group border custom-class="rounded-2! overflow-hidden">
<wd-cell <wd-cell
+5 -7
View File
@@ -112,12 +112,8 @@ const filteredGroups = computed(() => {
<view v-for="(group, gi) in filteredGroups" :key="gi" class="mb-4"> <view v-for="(group, gi) in filteredGroups" :key="gi" class="mb-4">
<view class="mb-2 mt-1 flex items-center gap-2 px-3"> <view class="mb-2 mt-1 flex items-center gap-2 px-3">
<view class="h-3.5 w-1 rounded-full" :style="{ backgroundColor: group.color }" /> <view class="h-3.5 w-1 rounded-full" :style="{ backgroundColor: group.color }" />
<text class="text-3.5 font-bold wot-text-text-main"> <wd-text class="text-3.5 wot-text-text-main" :text="t(group.titleKey)" bold />
{{ t(group.titleKey) }} <wd-text class="text-2.5 wot-text-text-auxiliary" :text="group.items.length" />
</text>
<text class="text-2.5 wot-text-text-auxiliary">
{{ group.items.length }}
</text>
</view> </view>
<wd-cell-group border custom-class="mx-3 rounded-2! overflow-hidden"> <wd-cell-group border custom-class="mx-3 rounded-2! overflow-hidden">
<wd-cell <wd-cell
@@ -135,7 +131,9 @@ const filteredGroups = computed(() => {
> >
<wd-icon :name="item.icon" size="16px" :color="group.color" /> <wd-icon :name="item.icon" size="16px" :color="group.color" />
</view> </view>
<text>{{ t(item.titleKey) }}</text> <text>
{{ t(item.titleKey) }}
</text>
</view> </view>
</template> </template>
</wd-cell> </wd-cell>
+1 -3
View File
@@ -78,9 +78,7 @@ function handleNavigate(url: string) {
<!-- 版权信息 --> <!-- 版权信息 -->
<view v-if="copyright" class="mx-3 mt-8 text-center"> <view v-if="copyright" class="mx-3 mt-8 text-center">
<text class="text-2.5 wot-text-text-auxiliary"> <wd-text class="text-2.5 wot-text-text-auxiliary" :text="copyright" />
{{ copyright }}
</text>
</view> </view>
<!-- 底部安全区(全面屏 Home 条避让) --> <!-- 底部安全区(全面屏 Home 条避让) -->
@@ -155,18 +155,12 @@ onLoad(() => {
<wd-cell :title="t('aiModels.groupTitle')" :value="t('aiModels.count', { count: models.length })" border /> <wd-cell :title="t('aiModels.groupTitle')" :value="t('aiModels.count', { count: models.length })" border />
<wd-cell v-for="model in models" :key="model.config_id" center> <wd-cell v-for="model in models" :key="model.config_id" center>
<template #title> <template #title>
<text class="truncate text-3.5 font-medium wot-text-text-main"> <wd-text class="truncate text-3.5 font-medium wot-text-text-main" :text="model.name || t('aiModels.unnamed')" />
{{ model.name || t('aiModels.unnamed') }}
</text>
</template> </template>
<template #label> <template #label>
<view class="flex flex-col"> <view class="flex flex-col">
<text class="truncate text-2.5 wot-text-text-auxiliary"> <wd-text class="truncate text-2.5 wot-text-text-auxiliary" :text="`${model.model_id} · ${t('aiModels.temperature')} ${model.temperature ?? '—'}`" />
{{ model.model_id }} · {{ t('aiModels.temperature') }} {{ model.temperature ?? '—' }} <wd-text class="truncate text-2.5 wot-text-text-auxiliary" :text="model.base_url" />
</text>
<text class="truncate text-2.5 wot-text-text-auxiliary">
{{ model.base_url }}
</text>
</view> </view>
</template> </template>
<template #default> <template #default>
@@ -219,9 +213,7 @@ onLoad(() => {
<wd-form-item :label="t('aiModels.temperatureLabel')" border> <wd-form-item :label="t('aiModels.temperatureLabel')" border>
<view class="w-full flex items-center gap-3"> <view class="w-full flex items-center gap-3">
<wd-slider v-model="temperature" class="flex-1" :min="0" :max="2" :step="0.1" show-extreme-value active-color="var(--primary-color)" /> <wd-slider v-model="temperature" class="flex-1" :min="0" :max="2" :step="0.1" show-extreme-value active-color="var(--primary-color)" />
<text class="w-16 text-right text-3 font-semibold wot-text-text-main"> <wd-text class="w-16 text-right text-3 font-semibold wot-text-text-main" :text="temperature.toFixed(1)" />
{{ temperature.toFixed(1) }}
</text>
</view> </view>
</wd-form-item> </wd-form-item>
</wd-collapse-item> </wd-collapse-item>
@@ -208,9 +208,7 @@ onLoad(() => {
<wd-button size="small" variant="plain" @click="showSessions = !showSessions"> <wd-button size="small" variant="plain" @click="showSessions = !showSessions">
<wd-icon name="menu" size="16px" /> <wd-icon name="menu" size="16px" />
</wd-button> </wd-button>
<text class="text-md flex-1 truncate text-center font-bold"> <wd-text class="text-md flex-1 truncate text-center" :text="currentTitle" bold />
{{ currentTitle }}
</text>
<wd-button size="small" type="primary" variant="plain" @click="createSession"> <wd-button size="small" type="primary" variant="plain" @click="createSession">
<wd-icon name="plus" size="16px" /> <wd-icon name="plus" size="16px" />
</wd-button> </wd-button>
@@ -220,9 +218,7 @@ onLoad(() => {
<view v-if="showSessions" class="session-overlay" style="position:absolute;top:88rpx;left:0;right:0;bottom:0;background:var(--bg-color);z-index:100;overflow-y:auto;"> <view v-if="showSessions" class="session-overlay" style="position:absolute;top:88rpx;left:0;right:0;bottom:0;background:var(--bg-color);z-index:100;overflow-y:auto;">
<view class="p-sm"> <view class="p-sm">
<view class="mb-md flex items-center justify-between px-xs"> <view class="mb-md flex items-center justify-between px-xs">
<text class="text-lg font-bold"> <wd-text class="text-lg" :text="t('chat.sessionList')" bold />
{{ t('chat.sessionList') }}
</text>
<wd-button size="small" type="primary" @click="createSession"> <wd-button size="small" type="primary" @click="createSession">
{{ t('chat.new') }} {{ t('chat.new') }}
</wd-button> </wd-button>
@@ -277,12 +273,8 @@ onLoad(() => {
<wd-loading v-if="streaming && !msg.content" /> <wd-loading v-if="streaming && !msg.content" />
<mp-html v-else :content="msg.content" markdown :tag-style="MARKDOWN_TAG_STYLE" /> <mp-html v-else :content="msg.content" markdown :tag-style="MARKDOWN_TAG_STYLE" />
</template> </template>
<text v-else style="white-space:pre-wrap;font-size:var(--font-sm,24rpx);line-height:1.7;"> <wd-text v-else style="white-space:pre-wrap;font-size:var(--font-sm,24rpx);line-height:1.7;" :text="msg.content" />
{{ msg.content }} <wd-text v-if="msg.time" style="font-size:var(--font-xs,20rpx);opacity:0.6;margin-top:8rpx;display:block;" :style="msg.role === 'user' ? 'text-align:right' : 'text-align:left'" :text="msg.time" />
</text>
<text v-if="msg.time" style="font-size:var(--font-xs,20rpx);opacity:0.6;margin-top:8rpx;display:block;" :style="msg.role === 'user' ? 'text-align:right' : 'text-align:left'">
{{ msg.time }}
</text>
</view> </view>
</view> </view>
</view> </view>
@@ -137,9 +137,7 @@ onLoad(() => loadData())
<!-- 列表头部:总数 --> <!-- 列表头部:总数 -->
<view class="mx-3 mb-2 mt-3 flex items-center justify-between px-1"> <view class="mx-3 mb-2 mt-3 flex items-center justify-between px-1">
<text class="text-3 wot-text-text-secondary"> <wd-text class="text-3 wot-text-text-secondary" :text="t('notices.count', { count: total })" />
{{ t('notices.count', { count: total }) }}
</text>
</view> </view>
<SkeletonPage v-if="loading && list.length === 0" :rows="5" search /> <SkeletonPage v-if="loading && list.length === 0" :rows="5" search />
@@ -151,17 +149,11 @@ onLoad(() => loadData())
<template #title> <template #title>
<view class="min-w-0 flex-1"> <view class="min-w-0 flex-1">
<view class="flex items-center justify-between gap-2"> <view class="flex items-center justify-between gap-2">
<text class="truncate text-3.5 font-medium wot-text-text-main"> <wd-text class="truncate text-3.5 font-medium wot-text-text-main" :text="item.notice_title" />
{{ item.notice_title }} <wd-text class="shrink-0 text-2.5 wot-text-text-auxiliary" :text="(item.created_time || '').slice(0, 10)" />
</text>
<text class="shrink-0 text-2.5 wot-text-text-auxiliary">
{{ (item.created_time || '').slice(0, 10) }}
</text>
</view> </view>
<view class="mt-1 flex items-center justify-between gap-2"> <view class="mt-1 flex items-center justify-between gap-2">
<text class="truncate text-2.5 wot-text-text-auxiliary"> <wd-text class="truncate text-2.5 wot-text-text-auxiliary" :text="item.description || ''" />
{{ item.description || '' }}
</text>
<view class="flex shrink-0 items-center gap-2"> <view class="flex shrink-0 items-center gap-2">
<StatusBadge :status="statusLabel(item.status)" /> <StatusBadge :status="statusLabel(item.status)" />
<wd-icon name="delete" size="18px" color="var(--danger-color)" @click.stop="handleDelete(item.id!)" /> <wd-icon name="delete" size="18px" color="var(--danger-color)" @click.stop="handleDelete(item.id!)" />
@@ -174,9 +166,7 @@ onLoad(() => loadData())
</view> </view>
<!-- 触底加载更多提示 --> <!-- 触底加载更多提示 -->
<wd-loading v-if="loading && list.length > 0" size="20px" class="mx-auto my-2 block" /> <wd-loading v-if="loading && list.length > 0" size="20px" class="mx-auto my-2 block" />
<text v-else-if="total > 0 && list.length >= total" class="my-2 block text-center text-2.5 wot-text-text-auxiliary"> <wd-text v-else-if="total > 0 && list.length >= total" class="my-2 block text-center text-2.5 wot-text-text-auxiliary" :text="t('common.noMore')" />
{{ t('common.noMore') }}
</text>
<!-- 底部安全区(全面屏 Home 条避让) --> <!-- 底部安全区(全面屏 Home 条避让) -->
<wd-gap height="100rpx" safe-area-bottom /> <wd-gap height="100rpx" safe-area-bottom />
</template> </template>
@@ -170,34 +170,24 @@ onLoad(() => {
</view> </view>
</view> </view>
</wd-upload> </wd-upload>
<text class="text-4 font-bold wot-text-text-main"> <wd-text class="text-4 wot-text-text-main" :text="userProfile?.name || userProfile?.username || '-'" bold />
{{ userProfile?.name || userProfile?.username || '-' }}
</text>
</view> </view>
<!-- 资料列表 --> <!-- 资料列表 -->
<view class="mx-3 mb-3"> <view class="mx-3 mb-3">
<wd-cell-group border custom-class="rounded-2! overflow-hidden"> <wd-cell-group border custom-class="rounded-2! overflow-hidden">
<wd-cell :title="t('profile.nickname')" is-link @click="openEdit('name')"> <wd-cell :title="t('profile.nickname')" is-link @click="openEdit('name')">
<text class="wot-text-text-secondary"> <wd-text class="wot-text-text-secondary" :text="userProfile?.name || t('profile.notSet')" />
{{ userProfile?.name || t('profile.notSet') }}
</text>
</wd-cell> </wd-cell>
<wd-cell :title="t('profile.gender')" is-link @click="openEdit('gender')"> <wd-cell :title="t('profile.gender')" is-link @click="openEdit('gender')">
<text class="wot-text-text-secondary"> <wd-text class="wot-text-text-secondary" :text="genderText" />
{{ genderText }}
</text>
</wd-cell> </wd-cell>
<wd-cell :title="t('profile.username')" :value="userProfile?.username || '-'" /> <wd-cell :title="t('profile.username')" :value="userProfile?.username || '-'" />
<wd-cell :title="t('profile.mobile')"> <wd-cell :title="t('profile.mobile')">
<text class="wot-text-text-secondary"> <wd-text class="wot-text-text-secondary" :text="userProfile?.mobile || t('profile.notBound')" />
{{ userProfile?.mobile || t('profile.notBound') }}
</text>
</wd-cell> </wd-cell>
<wd-cell :title="t('profile.email')"> <wd-cell :title="t('profile.email')">
<text class="wot-text-text-secondary"> <wd-text class="wot-text-text-secondary" :text="userProfile?.email || t('profile.notBound')" />
{{ userProfile?.email || t('profile.notBound') }}
</text>
</wd-cell> </wd-cell>
<wd-cell :title="t('profile.dept')" :value="deptText" /> <wd-cell :title="t('profile.dept')" :value="deptText" />
<wd-cell :title="t('profile.roles')" :value="roleText" /> <wd-cell :title="t('profile.roles')" :value="roleText" />
@@ -139,9 +139,7 @@ onLoad((options) => {
<template v-else-if="ticket"> <template v-else-if="ticket">
<!-- Ticket Header --> <!-- Ticket Header -->
<view class="mx-3 mb-3 rounded-2 p-4 wot-bg-filled-oppo"> <view class="mx-3 mb-3 rounded-2 p-4 wot-bg-filled-oppo">
<text class="block text-4 font-bold wot-text-text-main"> <wd-text class="block text-4 wot-text-text-main" :text="ticket.title || t('ticketDetail.unnamed')" bold />
{{ ticket.title || t('ticketDetail.unnamed') }}
</text>
<view class="mt-3 flex gap-2"> <view class="mt-3 flex gap-2">
<wd-tag size="small" round :bg-color="`${getTypeColor(ticket.ticket_type)}18`" :color="getTypeColor(ticket.ticket_type)"> <wd-tag size="small" round :bg-color="`${getTypeColor(ticket.ticket_type)}18`" :color="getTypeColor(ticket.ticket_type)">
{{ getTypeLabel(ticket.ticket_type) }} {{ getTypeLabel(ticket.ticket_type) }}
@@ -154,9 +152,7 @@ onLoad((options) => {
<!-- Ticket Status Steps --> <!-- Ticket Status Steps -->
<view class="mx-3 mb-3 rounded-2 p-4 wot-bg-filled-oppo"> <view class="mx-3 mb-3 rounded-2 p-4 wot-bg-filled-oppo">
<text class="mb-3 block text-3.5 font-bold wot-text-text-main"> <wd-text class="mb-3 block text-3.5 wot-text-text-main" :text="t('ticketDetail.progress')" bold />
{{ t('ticketDetail.progress') }}
</text>
<wd-steps :active="Number(ticket.status ?? 0)" align-center> <wd-steps :active="Number(ticket.status ?? 0)" align-center>
<wd-step :title="t('common.status.pending')" /> <wd-step :title="t('common.status.pending')" />
<wd-step :title="t('common.status.processing')" /> <wd-step :title="t('common.status.processing')" />
@@ -176,18 +172,14 @@ onLoad((options) => {
<!-- Ticket Content --> <!-- Ticket Content -->
<view v-if="ticket.ticket_content || ticket.summary" class="mx-3 mb-3 rounded-2 p-4 wot-bg-filled-oppo"> <view v-if="ticket.ticket_content || ticket.summary" class="mx-3 mb-3 rounded-2 p-4 wot-bg-filled-oppo">
<text class="block text-3.5 font-bold wot-text-text-main"> <wd-text class="block text-3.5 wot-text-text-main" :text="t('ticketDetail.content')" bold />
{{ t('ticketDetail.content') }}
</text>
<wd-divider class="my-3!" /> <wd-divider class="my-3!" />
<mp-html :content="ticket.summary || ticket.ticket_content" markdown :tag-style="MARKDOWN_TAG_STYLE" /> <mp-html :content="ticket.summary || ticket.ticket_content" markdown :tag-style="MARKDOWN_TAG_STYLE" />
</view> </view>
<!-- Images --> <!-- Images -->
<view v-if="parseImages(ticket.images).length > 0" class="mx-3 mb-3 rounded-2 p-4 wot-bg-filled-oppo"> <view v-if="parseImages(ticket.images).length > 0" class="mx-3 mb-3 rounded-2 p-4 wot-bg-filled-oppo">
<text class="block text-3.5 font-bold wot-text-text-main"> <wd-text class="block text-3.5 wot-text-text-main" :text="t('ticketDetail.attachments')" bold />
{{ t('ticketDetail.attachments') }}
</text>
<wd-divider class="my-3!" /> <wd-divider class="my-3!" />
<view class="flex flex-wrap gap-3"> <view class="flex flex-wrap gap-3">
<wd-img <wd-img
@@ -206,9 +198,7 @@ onLoad((options) => {
<!-- Reply --> <!-- Reply -->
<view v-if="ticket.reply" class="mx-3 mb-3 rounded-2 p-4 wot-bg-filled-oppo"> <view v-if="ticket.reply" class="mx-3 mb-3 rounded-2 p-4 wot-bg-filled-oppo">
<text class="block text-3.5 font-bold wot-text-text-main"> <wd-text class="block text-3.5 wot-text-text-main" :text="t('ticketDetail.replies')" bold />
{{ t('ticketDetail.replies') }}
</text>
<wd-divider class="my-3!" /> <wd-divider class="my-3!" />
<view class="rounded-lg p-3" style="background: var(--primary-color-light, rgba(1, 77, 178, 0.06));"> <view class="rounded-lg p-3" style="background: var(--primary-color-light, rgba(1, 77, 178, 0.06));">
<mp-html :content="ticket.reply" markdown :tag-style="MARKDOWN_TAG_STYLE" /> <mp-html :content="ticket.reply" markdown :tag-style="MARKDOWN_TAG_STYLE" />
@@ -217,9 +207,7 @@ onLoad((options) => {
<!-- Comments --> <!-- Comments -->
<view class="mx-3 mb-3 rounded-2 p-4 wot-bg-filled-oppo"> <view class="mx-3 mb-3 rounded-2 p-4 wot-bg-filled-oppo">
<text class="block text-3.5 font-bold wot-text-text-main"> <wd-text class="block text-3.5 wot-text-text-main" :text="t('ticketDetail.comments', { count: commentTotal })" bold />
{{ t('ticketDetail.comments', { count: commentTotal }) }}
</text>
<wd-divider class="my-3!" /> <wd-divider class="my-3!" />
<wd-empty v-if="comments.length === 0" :tip="t('ticketDetail.emptyComments')" /> <wd-empty v-if="comments.length === 0" :tip="t('ticketDetail.emptyComments')" />
<view v-else class="flex flex-col gap-4"> <view v-else class="flex flex-col gap-4">
@@ -231,23 +219,15 @@ onLoad((options) => {
/> />
<view class="min-w-0 flex-1"> <view class="min-w-0 flex-1">
<view class="flex items-center gap-3"> <view class="flex items-center gap-3">
<text class="text-3 font-semibold wot-text-text-main"> <wd-text class="text-3 font-semibold wot-text-text-main" :text="comment.username || t('ticketDetail.anonymous')" />
{{ comment.username || t('ticketDetail.anonymous') }} <wd-text class="text-2.5 wot-text-text-auxiliary" :text="comment.created_time || ''" />
</text>
<text class="text-2.5 wot-text-text-auxiliary">
{{ comment.created_time || '' }}
</text>
</view> </view>
<text class="mt-1 block text-3 leading-relaxed wot-text-text-secondary"> <wd-text class="mt-1 block text-3 leading-relaxed wot-text-text-secondary" :text="comment.content" />
{{ comment.content }}
</text>
</view> </view>
</view> </view>
<view v-if="commentTotal > comments.length" class="flex items-center justify-center py-1" @click="commentPage.page_no++; loadComments()"> <view v-if="commentTotal > comments.length" class="flex items-center justify-center py-1" @click="commentPage.page_no++; loadComments()">
<text class="text-3 wot-text-primary"> <wd-text class="text-3" :text="t('ticketDetail.loadMore')" type="primary" />
{{ t('ticketDetail.loadMore') }}
</text>
</view> </view>
</view> </view>
</view> </view>
@@ -225,9 +225,7 @@ onLoad(() => loadData())
> >
<template #right> <template #right>
<view class="h-full flex items-center justify-center px-6" style="background-color: var(--danger-color); color: #fff;"> <view class="h-full flex items-center justify-center px-6" style="background-color: var(--danger-color); color: #fff;">
<text class="text-3"> <wd-text class="text-3" :text="t('common.delete')" />
{{ t('common.delete') }}
</text>
</view> </view>
</template> </template>
<wd-cell <wd-cell
@@ -239,9 +237,7 @@ onLoad(() => loadData())
> >
<template #value> <template #value>
<view class="flex flex-col items-end gap-1"> <view class="flex flex-col items-end gap-1">
<text class="text-2.5 wot-text-text-auxiliary"> <wd-text class="text-2.5 wot-text-text-auxiliary" :text="(item.created_time || '').slice(0, 10)" />
{{ (item.created_time || '').slice(0, 10) }}
</text>
<StatusBadge :status="ticketStatus(item.status)" /> <StatusBadge :status="ticketStatus(item.status)" />
</view> </view>
</template> </template>
@@ -251,9 +247,7 @@ onLoad(() => loadData())
</view> </view>
<!-- 触底加载更多提示 --> <!-- 触底加载更多提示 -->
<wd-loading v-if="loading && list.length > 0" size="20px" class="mx-auto my-2 block" /> <wd-loading v-if="loading && list.length > 0" size="20px" class="mx-auto my-2 block" />
<text v-else-if="total > 0 && list.length >= total" class="my-2 block text-center text-2.5 wot-text-text-auxiliary"> <wd-text v-else-if="total > 0 && list.length >= total" class="my-2 block text-center text-2.5 wot-text-text-auxiliary" :text="t('common.noMore')" />
{{ t('common.noMore') }}
</text>
<!-- 底部安全区(全面屏 Home 条避让) --> <!-- 底部安全区(全面屏 Home 条避让) -->
<wd-gap height="100rpx" safe-area-bottom /> <wd-gap height="100rpx" safe-area-bottom />
</template> </template>
+7 -17
View File
@@ -159,12 +159,10 @@ function handleNavigate(url: string) {
<text class="mb-3 block text-left text-5 font-bold wot-text-text-main"> <text class="mb-3 block text-left text-5 font-bold wot-text-text-main">
{{ brandTitle }} {{ brandTitle }}
</text> </text>
<text class="mb-3 block text-left text-30rpx leading-relaxed wot-text-text-secondary"> <wd-text class="mb-3 block text-left wot-text-text-secondary" size="30rpx" line-height="1.6" :text="brandDesc" />
{{ brandDesc }}
</text>
</view> </view>
<view class="mx-3 mb-3"> <view class="mx-3 mb-3 mt-3">
<view class="mb-2 px-1 text-3.5 font-bold wot-text-text-main"> <view class="mb-2 px-1 text-3.5 font-bold wot-text-text-main">
{{ t('setting.basic') }} {{ t('setting.basic') }}
</view> </view>
@@ -183,13 +181,11 @@ function handleNavigate(url: string) {
class="h-4 w-4 rounded-full" class="h-4 w-4 rounded-full"
:style="{ backgroundColor: currentThemeColor.primary }" :style="{ backgroundColor: currentThemeColor.primary }"
/> />
<text>{{ currentThemeName }}</text> <wd-text :text="currentThemeName" />
</view> </view>
</wd-cell> </wd-cell>
<wd-cell :title="t('setting.language')" is-link @click="showLangSheet = true"> <wd-cell :title="t('setting.language')" is-link @click="showLangSheet = true">
<text class="text-3 wot-text-text-secondary"> <wd-text class="text-3 wot-text-text-secondary" :text="currentLang" />
{{ currentLang }}
</text>
</wd-cell> </wd-cell>
<wd-cell :title="t('setting.watermark')" :is-link="false"> <wd-cell :title="t('setting.watermark')" :is-link="false">
<wd-switch <wd-switch
@@ -217,9 +213,7 @@ function handleNavigate(url: string) {
</view> </view>
<wd-cell-group border custom-class="rounded-2! overflow-hidden"> <wd-cell-group border custom-class="rounded-2! overflow-hidden">
<wd-cell :title="t('setting.version')" :is-link="false"> <wd-cell :title="t('setting.version')" :is-link="false">
<text class="text-3 wot-text-text-secondary"> <wd-text class="text-3 wot-text-text-secondary" :text="`v${version || '--'}`" />
v{{ version || '--' }}
</text>
</wd-cell> </wd-cell>
<wd-cell :title="t('common.aboutUs')" is-link @click="navigateToAbout" /> <wd-cell :title="t('common.aboutUs')" is-link @click="navigateToAbout" />
<wd-cell :title="t('setting.clearCache')" is-link :value="cacheSize" @click="handleClearCache" /> <wd-cell :title="t('setting.clearCache')" is-link :value="cacheSize" @click="handleClearCache" />
@@ -248,9 +242,7 @@ function handleNavigate(url: string) {
class="h-6 w-6 border-2 rounded-full wot-border-border-main" class="h-6 w-6 border-2 rounded-full wot-border-border-main"
:style="{ backgroundColor: option.primary }" :style="{ backgroundColor: option.primary }"
/> />
<text class="text-4 wot-text-text-main"> <wd-text class="text-4 wot-text-text-main" :text="t(option.labelKey)" />
{{ t(option.labelKey) }}
</text>
</view> </view>
<wd-icon <wd-icon
v-if="currentThemeColor.value === option.value" v-if="currentThemeColor.value === option.value"
@@ -277,9 +269,7 @@ function handleNavigate(url: string) {
class="flex items-center justify-between border-b py-3 wot-border-border-main last:border-b-0" class="flex items-center justify-between border-b py-3 wot-border-border-main last:border-b-0"
@click="handleLangSelect(option)" @click="handleLangSelect(option)"
> >
<text class="text-4 wot-text-text-main"> <wd-text :text="t(option.labelKey)" class="text-4 wot-text-text-main" />
{{ t(option.labelKey) }}
</text>
<wd-icon <wd-icon
v-if="currentLocale === option.value" v-if="currentLocale === option.value"
name="check" name="check"
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long