perf:修复大多数文件的 linter(首次)

This commit is contained in:
YunaiV
2025-12-15 23:12:42 +08:00
parent f9fc5a8abe
commit d971aba582
39 changed files with 286 additions and 278 deletions

View File

@@ -3,9 +3,6 @@ import type {
IAuthLoginRes,
ICaptcha,
IDoubleTokenRes,
IUpdateInfo,
IUpdatePassword,
IUserInfoRes,
} from './types/login'
import { http } from '@/http/http'

View File

@@ -15,7 +15,7 @@ export interface Dept {
}
/** 获取部门列表 */
export function getDeptList(params?: { name?: string; status?: number }) {
export function getDeptList(params?: { name?: string, status?: number }) {
return http.get<Dept[]>('/system/dept/list', params)
}

View File

@@ -1,5 +1,5 @@
import type { PageParam, PageResult } from '@/http/types'
import { http } from '@/http/http'
import { PageParam, PageResult } from '@/http/types';
/** 角色信息 */
export interface Role {

View File

@@ -36,9 +36,9 @@ export interface IUserInfoRes {
* 权限信息
*/
export interface AuthPermissionInfo {
user: IUserInfoRes;
roles: string[];
permissions: string[];
user: IUserInfoRes
roles: string[]
permissions: string[]
// menus: AppRouteRecordRaw[]; // add by 芋艿:暂时用不到
}

View File

@@ -1,3 +1,4 @@
/* eslint-disable brace-style */ // 原因unibest 官方维护的代码,尽量不要大概,避免难以合并
import type { Ref } from 'vue'
import { onMounted, ref } from 'vue'

View File

@@ -1,3 +1,4 @@
/* eslint-disable brace-style */ // 原因unibest 官方维护的代码,尽量不要大概,避免难以合并
import type { CustomRequestOptions } from '@/http/types'
import { useTokenStore, useUserStore } from '@/store'
import { getEnvBaseUrl } from '@/utils'
@@ -55,7 +56,7 @@ const httpInterceptor = {
const token = tokenStore.validToken
let isToken = (options!.header || {}).isToken === false
whiteList.some((v) => {
if (options.url && options.url.indexOf(v) > -1) {
if (options.url && options.url.includes(v)) {
return (isToken = false)
}
})

View File

@@ -66,8 +66,8 @@ const props = defineProps<{
}>()
const emit = defineEmits<{
'search': [data: SearchFormData]
'reset': []
search: [data: SearchFormData]
reset: []
}>()
const visible = ref(false)

View File

@@ -78,8 +78,8 @@ import type { LoadMoreState } from '@/http/types'
import { onReachBottom } from '@dcloudio/uni-app'
import { onMounted, reactive, ref } from 'vue'
import { getApiAccessLogPage } from '@/api/infra/apiAccessLog'
import { formatDateTime } from '@/utils/date'
import { navigateBackPlus } from '@/utils'
import { formatDateTime } from '@/utils/date'
import SearchForm from './components/search-form.vue'
definePage({

View File

@@ -84,8 +84,8 @@ const props = defineProps<{
}>()
const emit = defineEmits<{
'search': [data: SearchFormData]
'reset': []
search: [data: SearchFormData]
reset: []
}>()
const visible = ref(false)

View File

@@ -68,9 +68,9 @@ import type { LoadMoreState } from '@/http/types'
import { onReachBottom } from '@dcloudio/uni-app'
import { onMounted, reactive, ref } from 'vue'
import { getApiErrorLogPage } from '@/api/infra/apiErrorLog'
import { navigateBackPlus } from '@/utils'
import { DICT_TYPE } from '@/utils/constants'
import { formatDateTime } from '@/utils/date'
import { navigateBackPlus } from '@/utils'
import SearchForm from './components/search-form.vue'
definePage({

View File

@@ -74,8 +74,8 @@ const props = defineProps<{
}>()
const emit = defineEmits<{
'search': [data: SearchFormData]
'reset': []
search: [data: SearchFormData]
reset: []
}>()
const visible = ref(false)

View File

@@ -11,9 +11,9 @@
</template>
<script lang="ts" setup>
import type {Dept} from '@/api/system/dept'
import {getSimpleDeptList} from '@/api/system/dept'
import {onMounted, ref, watch} from 'vue'
import type { Dept } from '@/api/system/dept'
import { onMounted, ref, watch } from 'vue'
import { getSimpleDeptList } from '@/api/system/dept'
const props = withDefaults(defineProps<{
modelValue?: number
@@ -47,15 +47,15 @@ watch(
// 顶级部门或未选择,重置
selectedValue.value = [0]
} else {
selectedValue.value = []
selectedValue.value = []
}
// 重新构建第一列,确保正确
if (deptList.value.length > 0) {
initFirstColumn()
initFirstColumn()
}
}
},
{ immediate: true }
{ immediate: true },
)
/** 初始化第一列 */
@@ -65,12 +65,12 @@ function initFirstColumn() {
deptColumns.value = [
[
{ label: '顶级部门', value: 0 },
...topDepts.map(item => ({ value: item.id, label: item.name }))
]
...topDepts.map(item => ({ value: item.id, label: item.name })),
],
]
} else {
deptColumns.value = [
topDepts.map(item => ({ value: item.id, label: item.name }))
topDepts.map(item => ({ value: item.id, label: item.name })),
]
}
}

View File

@@ -80,10 +80,10 @@ import type { Dept } from '@/api/system/dept'
import { computed, onMounted, ref } from 'vue'
import { useToast } from 'wot-design-uni'
import { createDept, getDept, updateDept } from '@/api/system/dept'
import UserPicker from '@/pages-system/user/form/components/user-picker.vue'
import { navigateBackPlus } from '@/utils'
import { CommonStatusEnum } from '@/utils/constants'
import DeptPicker from './components/dept-picker.vue'
import UserPicker from '@/pages-system/user/form/components/user-picker.vue'
import {navigateBackPlus} from '@/utils';
const props = defineProps<{
id?: number | any

View File

@@ -35,7 +35,7 @@ const props = withDefaults(defineProps<{
const emit = defineEmits<{
'update:modelValue': [value: number]
back: [] // 返回上一层级事件
'back': [] // 返回上一层级事件
}>()
const breadcrumbs = ref<BreadcrumbNode[]>([]) // 面包屑路径(不包含根目录)
@@ -47,12 +47,13 @@ const breadcrumbItems = computed(() => [
const currentParentId = computed({
get: () => props.modelValue,
set: (val) => emit('update:modelValue', val),
set: val => emit('update:modelValue', val),
}) // 当前父节点编号
/** 面包屑点击 */
function handleClick(index: number) {
if (index === breadcrumbItems.value.length - 1) return // 点击当前层级不处理
if (index === breadcrumbItems.value.length - 1)
return // 点击当前层级不处理
if (index === 0) {
breadcrumbs.value = []
currentParentId.value = 0

View File

@@ -34,7 +34,7 @@
菜单状态
</view>
<wd-radio-group v-model="formData.status" shape="button">
<wd-radio v-for="dict in getIntDictOptions(DICT_TYPE.COMMON_STATUS)" :key="dict.value" :value="dict.value">
<wd-radio v-for="dict in getIntDictOptions(DICT_TYPE.COMMON_STATUS)" :key="dict.value" :value="dict.value">
{{ dict.label }}
</wd-radio>
</wd-radio-group>
@@ -53,8 +53,8 @@
<script lang="ts" setup>
import { computed, reactive, ref, watch } from 'vue'
import { DICT_TYPE } from '@/utils/constants'
import { getIntDictOptions } from '@/hooks/useDict'
import { DICT_TYPE } from '@/utils/constants'
/** 搜索表单数据 */
export interface SearchFormData {
@@ -67,8 +67,8 @@ const props = defineProps<{
}>()
const emit = defineEmits<{
'search': [data: SearchFormData]
'reset': []
search: [data: SearchFormData]
reset: []
}>()
const visible = ref(false)

View File

@@ -126,8 +126,8 @@ import { computed, onMounted, ref } from 'vue'
import { useToast } from 'wot-design-uni'
import { createMenu, getMenu, updateMenu } from '@/api/system/menu'
import { getIntDictOptions } from '@/hooks/useDict'
import { CommonStatusEnum, DICT_TYPE, SystemMenuTypeEnum } from '@/utils/constants'
import { navigateBackPlus } from '@/utils'
import { CommonStatusEnum, DICT_TYPE, SystemMenuTypeEnum } from '@/utils/constants'
import MenuPicker from './components/menu-picker.vue'
const props = defineProps<{

View File

@@ -85,8 +85,8 @@ const props = defineProps<{
}>()
const emit = defineEmits<{
'search': [data: SearchFormData]
'reset': []
search: [data: SearchFormData]
reset: []
}>()
const visible = ref(false)

View File

@@ -30,7 +30,7 @@ const selectedIds = ref<number[]>([])
const columns = computed(() => {
return postList.value.map(item => ({
label: item.name,
value: item.id
value: item.id,
}))
})
@@ -39,7 +39,7 @@ watch(
(val) => {
selectedIds.value = val || []
},
{ immediate: true }
{ immediate: true },
)
async function loadPostList() {

View File

@@ -85,8 +85,8 @@ const props = defineProps<{
}>()
const emit = defineEmits<{
'search': [data: SearchFormData]
'reset': []
search: [data: SearchFormData]
reset: []
}>()
const visible = ref(false)

View File

@@ -65,8 +65,8 @@ const props = defineProps<{
}>()
const emit = defineEmits<{
'search': [data: SearchFormData]
'reset': []
search: [data: SearchFormData]
reset: []
}>()
const visible = ref(false)

View File

@@ -73,11 +73,11 @@ import { computed, onMounted, ref } from 'vue'
import { useToast } from 'wot-design-uni'
import { deleteUser, getUser, updateUserStatus } from '@/api/system/user'
import { useAccess } from '@/hooks/useAccess'
import { navigateBackPlus } from '@/utils'
import { CommonStatusEnum, DICT_TYPE } from '@/utils/constants'
import { formatDateTime } from '@/utils/date'
import PasswordForm from './components/password-form.vue'
import RoleAssignForm from './components/role-assign-form.vue'
import { navigateBackPlus } from '@/utils';
const props = defineProps<{
id?: number | any

View File

@@ -21,7 +21,7 @@ const props = withDefaults(defineProps<{
label?: string
}>(), {
type: 'checkbox',
label: '负责人'
label: '负责人',
})
const emit = defineEmits<{
@@ -35,7 +35,7 @@ const selectedId = ref<number | string | number[]>([])
const columns = computed(() => {
return userList.value.map(user => ({
label: user.nickname,
value: user.id
value: user.id,
}))
})
@@ -50,7 +50,7 @@ watch(
selectedId.value = Array.isArray(val) ? val : []
}
},
{ immediate: true }
{ immediate: true },
)
async function loadUserList() {

View File

@@ -105,11 +105,11 @@ import { computed, onMounted, ref } from 'vue'
import { useToast } from 'wot-design-uni'
import { createUser, getUser, updateUser } from '@/api/system/user'
import { getIntDictOptions } from '@/hooks/useDict'
import { CommonStatusEnum, DICT_TYPE } from '@/utils/constants'
import { isEmail, isMobile } from '@/utils/validator'
import DeptPicker from '@/pages-system/dept/form/components/dept-picker.vue'
import PostPicker from '@/pages-system/post/form/components/post-picker.vue'
import { navigateBackPlus } from '@/utils';
import { navigateBackPlus } from '@/utils'
import { CommonStatusEnum, DICT_TYPE } from '@/utils/constants'
import { isEmail, isMobile } from '@/utils/validator'
const props = defineProps<{
id?: number | any

View File

@@ -88,8 +88,8 @@ import { getUserPage } from '@/api/system/user'
import { useAccess } from '@/hooks/useAccess'
import { navigateBackPlus } from '@/utils'
import { DICT_TYPE } from '@/utils/constants'
import { formatDate } from '@/utils/date'
import SearchForm from './components/search-form.vue'
import { formatDate } from '@/utils/date';
definePage({
style: {

View File

@@ -52,63 +52,63 @@
</template>
<script lang="ts" setup>
import { reactive, ref } from "vue";
import { useToast } from "wot-design-uni";
import { FORGET_PASSWORD_PAGE, LOGIN_PAGE } from "@/router/config";
import { useTokenStore } from "@/store/token";
import { ensureDecodeURIComponent, redirectAfterLogin } from "@/utils";
import { isMobile } from "@/utils/validator";
import CodeInput from "./components/code-input.vue";
import Header from "./components/header.vue";
import TenantPicker from "./components/tenant-picker.vue";
import { Verify } from '@/components/verifition';
import { reactive, ref } from 'vue'
import { useToast } from 'wot-design-uni'
import { Verify } from '@/components/verifition'
import { FORGET_PASSWORD_PAGE, LOGIN_PAGE } from '@/router/config'
import { useTokenStore } from '@/store/token'
import { ensureDecodeURIComponent, redirectAfterLogin } from '@/utils'
import { isMobile } from '@/utils/validator'
import CodeInput from './components/code-input.vue'
import Header from './components/header.vue'
import TenantPicker from './components/tenant-picker.vue'
defineOptions({
name: "SmsLoginPage",
});
name: 'SmsLoginPage',
})
definePage({
style: {
navigationStyle: "custom",
navigationStyle: 'custom',
},
excludeLoginPath: true,
});
})
const toast = useToast();
const loading = ref(false); // 加载状态
const redirectUrl = ref<string>(); // 重定向地址
const tenantPickerRef = ref<InstanceType<typeof TenantPicker>>(); // 租户选择器引用
const captchaEnabled = import.meta.env.VITE_APP_CAPTCHA_ENABLE === 'true'; // 验证码开关
const verifyRef = ref();
const captchaType = ref('blockPuzzle'); // 滑块验证码 blockPuzzle|clickWord
const toast = useToast()
const loading = ref(false) // 加载状态
const redirectUrl = ref<string>() // 重定向地址
const tenantPickerRef = ref<InstanceType<typeof TenantPicker>>() // 租户选择器引用
const captchaEnabled = import.meta.env.VITE_APP_CAPTCHA_ENABLE === 'true' // 验证码开关
const verifyRef = ref()
const captchaType = ref('blockPuzzle') // 滑块验证码 blockPuzzle|clickWord
const formData = reactive({
mobile: "",
code: "",
captchaVerification: "", // 验证码校验值
}); // 表单数据
mobile: '',
code: '',
captchaVerification: '', // 验证码校验值
}) // 表单数据
/** 页面加载时处理重定向 */
onLoad((options) => {
if (options?.redirect) {
redirectUrl.value = ensureDecodeURIComponent(options.redirect);
redirectUrl.value = ensureDecodeURIComponent(options.redirect)
}
});
})
/** 发送验证码前的校验 */
function validateBeforeSend(): boolean {
return tenantPickerRef.value?.validate() ?? false;
return tenantPickerRef.value?.validate() ?? false
}
/** 获取验证码 */
async function getCode() {
// 情况一,未开启:则直接登录
if (!captchaEnabled) {
await verifySuccess({});
await verifySuccess({})
} else {
// 情况二,已开启:则展示验证码;只有完成验证码的情况,才进行登录
// 弹出验证码
verifyRef.value.show();
verifyRef.value.show()
}
}
@@ -116,52 +116,52 @@ async function getCode() {
async function handleLogin() {
// 校验租户
if (!tenantPickerRef.value?.validate()) {
return;
return
}
if (!formData.mobile) {
toast.warning("请输入手机号");
return;
toast.warning('请输入手机号')
return
}
if (!isMobile(formData.mobile)) {
toast.warning("请输入正确的手机号");
return;
toast.warning('请输入正确的手机号')
return
}
if (!formData.code) {
toast.warning("请输入验证码");
return;
toast.warning('请输入验证码')
return
}
await getCode();
await getCode()
}
/** 验证码验证成功回调 */
async function verifySuccess(params: any) {
loading.value = true;
loading.value = true
try {
// 调用短信登录接口
const tokenStore = useTokenStore();
formData.captchaVerification = params.captchaVerification;
const tokenStore = useTokenStore()
formData.captchaVerification = params.captchaVerification
await tokenStore.login({
type: "sms",
type: 'sms',
...formData,
});
})
// 处理跳转
redirectAfterLogin(redirectUrl.value);
redirectAfterLogin(redirectUrl.value)
} finally {
loading.value = false;
loading.value = false
}
}
/** 跳转到账号密码登录 */
function goToLogin() {
uni.navigateTo({ url: LOGIN_PAGE });
uni.navigateTo({ url: LOGIN_PAGE })
}
/** 跳转到忘记密码 */
function goToForgetPassword() {
uni.navigateTo({ url: FORGET_PASSWORD_PAGE });
uni.navigateTo({ url: FORGET_PASSWORD_PAGE })
}
</script>
<style lang="scss" scoped>
@import "./styles/auth.scss";
@import './styles/auth.scss';
</style>

View File

@@ -23,68 +23,68 @@
</template>
<script lang="ts" setup>
import { onUnmounted, ref } from "vue";
import { useToast } from "wot-design-uni";
import { sendSmsCode } from "@/api/login";
import { isMobile } from "@/utils/validator";
import { onUnmounted, ref } from 'vue'
import { useToast } from 'wot-design-uni'
import { sendSmsCode } from '@/api/login'
import { isMobile } from '@/utils/validator'
defineOptions({
name: "CodeInput",
});
name: 'CodeInput',
})
const props = defineProps<{
modelValue: string; // 验证码值 (v-model)
mobile: string; // 手机号
scene: number; // 短信场景21-登录 23-重置密码
beforeSend?: () => boolean; // 发送前的校验函数,返回 false 则不发送
}>();
modelValue: string // 验证码值 (v-model)
mobile: string // 手机号
scene: number // 短信场景21-登录 23-重置密码
beforeSend?: () => boolean // 发送前的校验函数,返回 false 则不发送
}>()
defineEmits<{
"update:modelValue": [value: string];
}>();
'update:modelValue': [value: string]
}>()
const toast = useToast();
const countdown = ref(0); // 验证码倒计时,单位秒
let countdownTimer: ReturnType<typeof setInterval> | null = null; // 倒计时定时器
const toast = useToast()
const countdown = ref(0) // 验证码倒计时,单位秒
let countdownTimer: ReturnType<typeof setInterval> | null = null // 倒计时定时器
/** 页面卸载时清除倒计时定时器 */
onUnmounted(() => {
if (countdownTimer) {
clearInterval(countdownTimer);
countdownTimer = null;
clearInterval(countdownTimer)
countdownTimer = null
}
});
})
/** 发送验证码 */
async function handleSendCode() {
// 执行前置校验
if (props.beforeSend && !props.beforeSend()) {
return;
return
}
if (countdown.value > 0) {
return;
return
}
if (!props.mobile) {
toast.warning("请输入手机号");
return;
toast.warning('请输入手机号')
return
}
if (!isMobile(props.mobile)) {
toast.warning("请输入正确的手机号");
return;
toast.warning('请输入正确的手机号')
return
}
// 发送验证码
await sendSmsCode({ mobile: props.mobile, scene: props.scene });
toast.success("验证码已发送");
await sendSmsCode({ mobile: props.mobile, scene: props.scene })
toast.success('验证码已发送')
// 开始倒计时
countdown.value = 60;
countdown.value = 60
countdownTimer = setInterval(() => {
countdown.value--;
countdown.value--
if (countdown.value <= 0) {
clearInterval(countdownTimer!);
countdownTimer = null;
clearInterval(countdownTimer!)
countdownTimer = null
}
}, 1000);
}, 1000)
}
</script>

View File

@@ -14,121 +14,122 @@
</template>
<script lang="ts" setup>
import { computed, onMounted, ref } from "vue";
import { useToast } from "wot-design-uni";
import type { TenantVO } from '@/api/login'
import { computed, onMounted, ref } from 'vue'
import { useToast } from 'wot-design-uni'
import {
getTenantByWebsite,
getTenantSimpleList,
type TenantVO,
} from "@/api/login";
import { useUserStore } from "@/store/user";
const toast = useToast();
const userStore = useUserStore();
} from '@/api/login'
import { useUserStore } from '@/store/user'
const toast = useToast()
const userStore = useUserStore()
const tenantEnabled = computed(
() => import.meta.env.VITE_APP_TENANT_ENABLE === "true",
); // 租户开关:通过环境变量控制
const tenantList = ref<TenantVO[]>([]); // 租户列表数据
() => import.meta.env.VITE_APP_TENANT_ENABLE === 'true',
) // 租户开关:通过环境变量控制
const tenantList = ref<TenantVO[]>([]) // 租户列表数据
const tenantId = computed(
() =>
userStore.tenantId ||
Number(import.meta.env.VITE_APP_DEFAULT_LOGIN_TENANT_ID) ||
undefined,
); // 当前选中的租户
userStore.tenantId
|| Number(import.meta.env.VITE_APP_DEFAULT_LOGIN_TENANT_ID)
|| undefined,
) // 当前选中的租户
/** 获取租户列表,并根据域名/appId 自动选中租户 */
async function fetchTenantList() {
if (!tenantEnabled.value) {
return;
return
}
try {
// 1. 并行获取租户列表和域名对应的租户
const websiteTenantPromise = fetchTenantByWebsite();
const list = await getTenantSimpleList();
tenantList.value = list || [];
const websiteTenantPromise = fetchTenantByWebsite()
const list = await getTenantSimpleList()
tenantList.value = list || []
// 2. 确定选中的租户:域名/appId > store 中的租户 > 列表第一个
let selectedTenantId: number | null = null;
let selectedTenantId: number | null = null
// 2.1 优先使用域名/appId 对应的租户
const websiteTenant = await websiteTenantPromise;
const websiteTenant = await websiteTenantPromise
if (websiteTenant?.id) {
selectedTenantId = websiteTenant.id;
selectedTenantId = websiteTenant.id
}
// 2.2 如果没有从域名获取到,使用 store 中的租户
if (!selectedTenantId && userStore.tenantId) {
selectedTenantId = userStore.tenantId;
selectedTenantId = userStore.tenantId
}
// 2.3 如果还是没有,使用列表第一个
if (!selectedTenantId && tenantList.value.length > 0) {
selectedTenantId = tenantList.value[0].id;
selectedTenantId = tenantList.value[0].id
}
// 3. 设置选中的租户
if (selectedTenantId && selectedTenantId !== userStore.tenantId) {
userStore.setTenantId(selectedTenantId);
userStore.setTenantId(selectedTenantId)
}
} catch (error) {
console.error("获取租户列表失败:", error);
console.error('获取租户列表失败:', error)
}
}
/** 根据域名或 appId 获取租户 */
async function fetchTenantByWebsite(): Promise<TenantVO | null> {
try {
let website: string | null = null;
let website: string | null = null
// #ifdef H5
// H5 环境:使用域名
if (window?.location?.hostname) {
website = window.location.hostname;
website = window.location.hostname
}
// #endif
// #ifdef MP
// 小程序环境:使用 appId
const appId = uni.getAccountInfoSync?.()?.miniProgram?.appId;
const appId = uni.getAccountInfoSync?.()?.miniProgram?.appId
if (appId) {
website = appId;
website = appId
}
// #endif
if (website) {
return await getTenantByWebsite(website);
return await getTenantByWebsite(website)
}
} catch (error) {
// 域名未配置租户时会报错,忽略即可
console.debug("根据域名获取租户失败:", error);
console.debug('根据域名获取租户失败:', error)
}
return null;
return null
}
/** 租户选择确认 */
function handleConfirm({ value }: { value: number }) {
userStore.setTenantId(value);
userStore.setTenantId(value)
}
/** 校验租户是否已选择 */
function validate(): boolean {
if (!tenantEnabled.value) {
return true;
return true
}
if (!tenantId.value) {
toast.warning("请选择租户");
return false;
toast.warning('请选择租户')
return false
}
return true;
return true
}
/** 页面加载时获取租户列表 */
onMounted(() => {
fetchTenantList();
});
fetchTenantList()
})
defineExpose({ validate });
defineExpose({ validate })
</script>
<style lang="scss" scoped>
@import "../styles/auth.scss";
@import '../styles/auth.scss';
</style>

View File

@@ -64,97 +64,97 @@
</template>
<script lang="ts" setup>
import { reactive, ref } from "vue";
import { useToast } from "wot-design-uni";
import { smsResetPassword } from "@/api/login";
import { LOGIN_PAGE } from "@/router/config";
import { isMobile } from "@/utils/validator";
import CodeInput from "./components/code-input.vue";
import Header from "./components/header.vue";
import TenantPicker from "./components/tenant-picker.vue";
import { reactive, ref } from 'vue'
import { useToast } from 'wot-design-uni'
import { smsResetPassword } from '@/api/login'
import { LOGIN_PAGE } from '@/router/config'
import { isMobile } from '@/utils/validator'
import CodeInput from './components/code-input.vue'
import Header from './components/header.vue'
import TenantPicker from './components/tenant-picker.vue'
defineOptions({
name: "ForgetPasswordPage",
});
name: 'ForgetPasswordPage',
})
definePage({
style: {
navigationStyle: "custom",
navigationStyle: 'custom',
},
excludeLoginPath: true,
});
})
const toast = useToast();
const loading = ref(false); // 加载状态
const tenantPickerRef = ref<InstanceType<typeof TenantPicker>>(); // 租户选择器引用
const toast = useToast()
const loading = ref(false) // 加载状态
const tenantPickerRef = ref<InstanceType<typeof TenantPicker>>() // 租户选择器引用
const formData = reactive({
mobile: "",
code: "",
password: "",
confirmPassword: "",
}); // 表单数据
mobile: '',
code: '',
password: '',
confirmPassword: '',
}) // 表单数据
/** 发送验证码前的校验 */
function validateBeforeSend(): boolean {
return tenantPickerRef.value?.validate() ?? false;
return tenantPickerRef.value?.validate() ?? false
}
/** 重置密码处理 */
async function handleResetPassword() {
// 校验租户
if (!tenantPickerRef.value?.validate()) {
return;
return
}
if (!formData.mobile) {
toast.warning("请输入手机号");
return;
toast.warning('请输入手机号')
return
}
if (!isMobile(formData.mobile)) {
toast.warning("请输入正确的手机号");
return;
toast.warning('请输入正确的手机号')
return
}
if (!formData.code) {
toast.warning("请输入验证码");
return;
toast.warning('请输入验证码')
return
}
if (!formData.password) {
toast.warning("请输入新密码");
return;
toast.warning('请输入新密码')
return
}
if (!formData.confirmPassword) {
toast.warning("请确认新密码");
return;
toast.warning('请确认新密码')
return
}
if (formData.password !== formData.confirmPassword) {
toast.warning("两次输入的密码不一致");
return;
toast.warning('两次输入的密码不一致')
return
}
loading.value = true;
loading.value = true
try {
// 调用重置密码接口
await smsResetPassword({
mobile: formData.mobile,
code: formData.code,
password: formData.password,
});
toast.success("密码重置成功");
})
toast.success('密码重置成功')
// 跳转到登录页
setTimeout(() => {
goToLogin();
}, 500);
goToLogin()
}, 500)
} finally {
loading.value = false;
loading.value = false
}
}
/** 跳转到登录页面 */
function goToLogin() {
uni.navigateTo({ url: LOGIN_PAGE });
uni.navigateTo({ url: LOGIN_PAGE })
}
</script>
<style lang="scss" scoped>
@import "./styles/auth.scss";
@import './styles/auth.scss';
</style>

View File

@@ -82,6 +82,7 @@
<script lang="ts" setup>
import { reactive, ref } from 'vue'
import { useToast } from 'wot-design-uni'
import { Verify } from '@/components/verifition'
import {
CODE_LOGIN_PAGE,
FORGET_PASSWORD_PAGE,
@@ -91,7 +92,6 @@ import { useTokenStore } from '@/store/token'
import { ensureDecodeURIComponent, redirectAfterLogin } from '@/utils'
import Header from './components/header.vue'
import TenantPicker from './components/tenant-picker.vue'
import { Verify } from '@/components/verifition';
defineOptions({
name: 'LoginPage',

View File

@@ -92,120 +92,120 @@
</template>
<script lang="ts" setup>
import { reactive, ref } from "vue";
import { useToast } from "wot-design-uni";
import { LOGIN_PAGE } from "@/router/config";
import { useTokenStore } from "@/store/token";
import { redirectAfterLogin } from "@/utils";
import Header from "./components/header.vue";
import TenantPicker from "./components/tenant-picker.vue";
import { Verify } from '@/components/verifition';
import { reactive, ref } from 'vue'
import { useToast } from 'wot-design-uni'
import { Verify } from '@/components/verifition'
import { LOGIN_PAGE } from '@/router/config'
import { useTokenStore } from '@/store/token'
import { redirectAfterLogin } from '@/utils'
import Header from './components/header.vue'
import TenantPicker from './components/tenant-picker.vue'
defineOptions({
name: "RegisterPage",
});
name: 'RegisterPage',
})
definePage({
style: {
navigationStyle: "custom",
navigationStyle: 'custom',
},
});
})
const toast = useToast();
const loading = ref(false); // 加载状态
const agreePolicy = ref(false); // 用户协议勾选
const tenantPickerRef = ref<InstanceType<typeof TenantPicker>>(); // 租户选择器引用
const captchaEnabled = import.meta.env.VITE_APP_CAPTCHA_ENABLE === 'true'; // 验证码开关
const verifyRef = ref();
const captchaType = ref('blockPuzzle'); // 滑块验证码 blockPuzzle|clickWord
const toast = useToast()
const loading = ref(false) // 加载状态
const agreePolicy = ref(false) // 用户协议勾选
const tenantPickerRef = ref<InstanceType<typeof TenantPicker>>() // 租户选择器引用
const captchaEnabled = import.meta.env.VITE_APP_CAPTCHA_ENABLE === 'true' // 验证码开关
const verifyRef = ref()
const captchaType = ref('blockPuzzle') // 滑块验证码 blockPuzzle|clickWord
const formData = reactive({
username: "",
nickname: "",
password: "",
confirmPassword: "",
captchaVerification: "", // 验证码校验值
}); // 表单数据
username: '',
nickname: '',
password: '',
confirmPassword: '',
captchaVerification: '', // 验证码校验值
}) // 表单数据
/** 获取验证码 */
async function getCode() {
// 情况一,未开启:则直接注册
if (!captchaEnabled) {
await verifySuccess({});
await verifySuccess({})
} else {
// 情况二,已开启:则展示验证码;只有完成验证码的情况,才进行注册
// 弹出验证码
verifyRef.value.show();
verifyRef.value.show()
}
}
/** 注册处理 */
async function handleRegister() {
if (!tenantPickerRef.value?.validate()) {
return;
return
}
if (!agreePolicy.value) {
toast.warning("请阅读并同意《用户协议》与《隐私政策》");
return;
toast.warning('请阅读并同意《用户协议》与《隐私政策》')
return
}
if (!formData.username) {
toast.warning("请输入用户名");
return;
toast.warning('请输入用户名')
return
}
if (!formData.nickname) {
toast.warning("请输入昵称");
return;
toast.warning('请输入昵称')
return
}
if (!formData.password) {
toast.warning("请输入密码");
return;
toast.warning('请输入密码')
return
}
if (!formData.confirmPassword) {
toast.warning("请确认密码");
return;
toast.warning('请确认密码')
return
}
if (formData.password !== formData.confirmPassword) {
toast.warning("两次输入的密码不一致");
return;
toast.warning('两次输入的密码不一致')
return
}
await getCode();
await getCode()
}
/** 验证码验证成功回调 */
async function verifySuccess(params: any) {
loading.value = true;
loading.value = true
try {
// 调用注册接口
const tokenStore = useTokenStore();
formData.captchaVerification = params.captchaVerification;
const tokenStore = useTokenStore()
formData.captchaVerification = params.captchaVerification
await tokenStore.login({
type: "register",
type: 'register',
...formData,
});
toast.success("注册成功");
})
toast.success('注册成功')
// 处理跳转
redirectAfterLogin();
redirectAfterLogin()
} finally {
loading.value = false;
loading.value = false
}
}
/** 跳转到登录页面 */
function goToLogin() {
uni.navigateTo({ url: LOGIN_PAGE });
uni.navigateTo({ url: LOGIN_PAGE })
}
/** 跳转到用户协议 */
function goToUserAgreement() {
uni.navigateTo({ url: "/pages/user/settings/agreement/index" });
uni.navigateTo({ url: '/pages/user/settings/agreement/index' })
}
/** 跳转到隐私政策 */
function goToPrivacyPolicy() {
uni.navigateTo({ url: "/pages/user/settings/privacy/index" });
uni.navigateTo({ url: '/pages/user/settings/privacy/index' })
}
</script>
<style lang="scss" scoped>
@import "./styles/auth.scss";
@import './styles/auth.scss';
</style>

View File

@@ -38,7 +38,7 @@ const toast = useToast()
/** 处理菜单点击 */
function handleClick(menu: MenuItem) {
console.log( '点击菜单:', menu )
console.log('点击菜单:', menu)
if (!menu.url) {
toast.show('功能开发中')
return

View File

@@ -121,9 +121,9 @@ const props = defineProps<{
}>()
const emit = defineEmits<{
'search': [data: SearchFormData]
'reset': []
'readAll': []
search: [data: SearchFormData]
reset: []
readAll: []
}>()
const visible = ref(false)

View File

@@ -141,8 +141,7 @@ async function handleConfirm() {
toast.success('修改成功')
handleClose()
emit('success')
}
finally {
} finally {
submitting.value = false
}
}

View File

@@ -22,13 +22,17 @@
<template #icon>
<wd-icon name="chat" size="20px" color="#07c160" class="mr-16rpx" />
</template>
<view class="text-[#999]">未绑定</view>
<view class="text-[#999]">
未绑定
</view>
</wd-cell>
<wd-cell title="微信公众号" is-link @click="handleBindWechatOfficialAccount">
<template #icon>
<wd-icon name="chat" size="20px" color="#07c160" class="mr-16rpx" />
</template>
<view class="text-[#999]">未绑定</view>
<view class="text-[#999]">
未绑定
</view>
</wd-cell>
</wd-cell-group>

View File

@@ -1,3 +1,4 @@
/* eslint-disable brace-style */ // 原因unibest 官方维护的代码,尽量不要大概,避免难以合并
import { isMp } from '@uni-helper/uni-env'
/**
* by 菲鸽 on 2025-08-19

View File

@@ -1,4 +1,5 @@
<script setup lang="ts">
/* eslint-disable brace-style */ // 原因unibest 官方维护的代码,尽量不要大概,避免难以合并
// i-carbon-code
import type { CustomTabBarItem } from './types'
import { customTabbarEnable, needHideNativeTabbar, tabbarCacheEnable } from './config'

View File

@@ -1,3 +1,4 @@
/* eslint-disable brace-style */ // 原因unibest 官方维护的代码,尽量不要大概,避免难以合并
import type { CustomTabBarItem, CustomTabBarItemBadge } from './types'
import { reactive } from 'vue'

View File

@@ -1,3 +1,4 @@
/* eslint-disable brace-style */ // 原因unibest 官方维护的代码,尽量不要大概,避免难以合并
import { LOGIN_PAGE } from '@/router/config'
import { getLastPage } from '@/utils'
import { debounce } from '@/utils/debounce'

View File

@@ -40,4 +40,4 @@ export function getAndClearTabParams(): Record<string, string> | undefined {
delete app.globalData.tabParams
}
return tabParams
}
}