perf:修复大多数文件的 linter(首次)
This commit is contained in:
@@ -3,9 +3,6 @@ import type {
|
||||
IAuthLoginRes,
|
||||
ICaptcha,
|
||||
IDoubleTokenRes,
|
||||
IUpdateInfo,
|
||||
IUpdatePassword,
|
||||
IUserInfoRes,
|
||||
} from './types/login'
|
||||
import { http } from '@/http/http'
|
||||
|
||||
|
||||
@@ -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)
|
||||
}
|
||||
|
||||
|
||||
@@ -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 {
|
||||
|
||||
@@ -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 芋艿:暂时用不到
|
||||
}
|
||||
|
||||
|
||||
@@ -1,3 +1,4 @@
|
||||
/* eslint-disable brace-style */ // 原因:unibest 官方维护的代码,尽量不要大概,避免难以合并
|
||||
import type { Ref } from 'vue'
|
||||
import { onMounted, ref } from 'vue'
|
||||
|
||||
|
||||
@@ -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)
|
||||
}
|
||||
})
|
||||
|
||||
@@ -66,8 +66,8 @@ const props = defineProps<{
|
||||
}>()
|
||||
|
||||
const emit = defineEmits<{
|
||||
'search': [data: SearchFormData]
|
||||
'reset': []
|
||||
search: [data: SearchFormData]
|
||||
reset: []
|
||||
}>()
|
||||
|
||||
const visible = ref(false)
|
||||
|
||||
@@ -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({
|
||||
|
||||
@@ -84,8 +84,8 @@ const props = defineProps<{
|
||||
}>()
|
||||
|
||||
const emit = defineEmits<{
|
||||
'search': [data: SearchFormData]
|
||||
'reset': []
|
||||
search: [data: SearchFormData]
|
||||
reset: []
|
||||
}>()
|
||||
|
||||
const visible = ref(false)
|
||||
|
||||
@@ -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({
|
||||
|
||||
@@ -74,8 +74,8 @@ const props = defineProps<{
|
||||
}>()
|
||||
|
||||
const emit = defineEmits<{
|
||||
'search': [data: SearchFormData]
|
||||
'reset': []
|
||||
search: [data: SearchFormData]
|
||||
reset: []
|
||||
}>()
|
||||
|
||||
const visible = ref(false)
|
||||
|
||||
@@ -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 })),
|
||||
]
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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)
|
||||
|
||||
@@ -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<{
|
||||
|
||||
@@ -85,8 +85,8 @@ const props = defineProps<{
|
||||
}>()
|
||||
|
||||
const emit = defineEmits<{
|
||||
'search': [data: SearchFormData]
|
||||
'reset': []
|
||||
search: [data: SearchFormData]
|
||||
reset: []
|
||||
}>()
|
||||
|
||||
const visible = ref(false)
|
||||
|
||||
@@ -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() {
|
||||
|
||||
@@ -85,8 +85,8 @@ const props = defineProps<{
|
||||
}>()
|
||||
|
||||
const emit = defineEmits<{
|
||||
'search': [data: SearchFormData]
|
||||
'reset': []
|
||||
search: [data: SearchFormData]
|
||||
reset: []
|
||||
}>()
|
||||
|
||||
const visible = ref(false)
|
||||
|
||||
@@ -65,8 +65,8 @@ const props = defineProps<{
|
||||
}>()
|
||||
|
||||
const emit = defineEmits<{
|
||||
'search': [data: SearchFormData]
|
||||
'reset': []
|
||||
search: [data: SearchFormData]
|
||||
reset: []
|
||||
}>()
|
||||
|
||||
const visible = ref(false)
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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() {
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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: {
|
||||
|
||||
@@ -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>
|
||||
|
||||
@@ -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>
|
||||
|
||||
@@ -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>
|
||||
|
||||
@@ -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>
|
||||
|
||||
@@ -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',
|
||||
|
||||
@@ -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>
|
||||
|
||||
@@ -38,7 +38,7 @@ const toast = useToast()
|
||||
|
||||
/** 处理菜单点击 */
|
||||
function handleClick(menu: MenuItem) {
|
||||
console.log( '点击菜单:', menu )
|
||||
console.log('点击菜单:', menu)
|
||||
if (!menu.url) {
|
||||
toast.show('功能开发中')
|
||||
return
|
||||
|
||||
@@ -121,9 +121,9 @@ const props = defineProps<{
|
||||
}>()
|
||||
|
||||
const emit = defineEmits<{
|
||||
'search': [data: SearchFormData]
|
||||
'reset': []
|
||||
'readAll': []
|
||||
search: [data: SearchFormData]
|
||||
reset: []
|
||||
readAll: []
|
||||
}>()
|
||||
|
||||
const visible = ref(false)
|
||||
|
||||
@@ -141,8 +141,7 @@ async function handleConfirm() {
|
||||
toast.success('修改成功')
|
||||
handleClose()
|
||||
emit('success')
|
||||
}
|
||||
finally {
|
||||
} finally {
|
||||
submitting.value = false
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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>
|
||||
|
||||
|
||||
@@ -1,3 +1,4 @@
|
||||
/* eslint-disable brace-style */ // 原因:unibest 官方维护的代码,尽量不要大概,避免难以合并
|
||||
import { isMp } from '@uni-helper/uni-env'
|
||||
/**
|
||||
* by 菲鸽 on 2025-08-19
|
||||
|
||||
@@ -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'
|
||||
|
||||
@@ -1,3 +1,4 @@
|
||||
/* eslint-disable brace-style */ // 原因:unibest 官方维护的代码,尽量不要大概,避免难以合并
|
||||
import type { CustomTabBarItem, CustomTabBarItemBadge } from './types'
|
||||
import { reactive } from 'vue'
|
||||
|
||||
|
||||
@@ -1,3 +1,4 @@
|
||||
/* eslint-disable brace-style */ // 原因:unibest 官方维护的代码,尽量不要大概,避免难以合并
|
||||
import { LOGIN_PAGE } from '@/router/config'
|
||||
import { getLastPage } from '@/utils'
|
||||
import { debounce } from '@/utils/debounce'
|
||||
|
||||
@@ -40,4 +40,4 @@ export function getAndClearTabParams(): Record<string, string> | undefined {
|
||||
delete app.globalData.tabParams
|
||||
}
|
||||
return tabParams
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user