feat: cache

This commit is contained in:
zc 2025-10-19 08:59:09 +08:00
parent d32d264066
commit 36ae82efa2
27 changed files with 888 additions and 154 deletions

View File

@ -34,4 +34,3 @@ Object.values(totalApiConfig).forEach((apiConfig) => {
export default totalApiConfig
export const api = totalApiConfig
export const abc = 123

View File

@ -1,6 +1,7 @@
const login = {
apiGetUserRoleInfo: ['/user/getRoleUserInfo'], // 获取用户信息及权限
apiLogout: ['/login/out'] // 退出登录
apiLogout: ['/login/out'], // 退出登录
login: ['/admin/login'] // 登录
}
export default login
export default login

View File

@ -7,7 +7,7 @@
export {}
declare global {
const EffectScope: typeof import('vue')['EffectScope']
const api: typeof import('src/api/index')['api']
const api: typeof import('../../../../../../src/api/index')['api']
const computed: typeof import('vue')['computed']
const createApp: typeof import('vue')['createApp']
const customRef: typeof import('vue')['customRef']
@ -18,8 +18,8 @@ declare global {
const getCurrentScope: typeof import('vue')['getCurrentScope']
const getCurrentWatcher: typeof import('vue')['getCurrentWatcher']
const h: typeof import('vue')['h']
const handleInit: typeof import('src/utils/page/index')['handleInit']
const handleMessageBox: typeof import('src/utils/page/index')['handleMessageBox']
const handleInit: typeof import('../../../../../../src/utils/page/index')['handleInit']
const handleMessageBox: typeof import('../../../../../../src/utils/page/index')['handleMessageBox']
const inject: typeof import('vue')['inject']
const isProxy: typeof import('vue')['isProxy']
const isReactive: typeof import('vue')['isReactive']
@ -44,7 +44,7 @@ declare global {
const onUnmounted: typeof import('vue')['onUnmounted']
const onUpdated: typeof import('vue')['onUpdated']
const onWatcherCleanup: typeof import('vue')['onWatcherCleanup']
const pageConfig: typeof import('src/utils/page/config')['pageConfig']
const pageConfig: typeof import('../../../../../../src/utils/page/config')['pageConfig']
const provide: typeof import('vue')['provide']
const reactive: typeof import('vue')['reactive']
const readonly: typeof import('vue')['readonly']

638
src/config/menuList.ts Normal file
View File

@ -0,0 +1,638 @@
export default [
{
id: 37,
resourceName: '商品配置',
resourceType: 0,
resourceCode: null,
path: '/goods',
pid: 0,
resourceDesc: null,
tenantId: 2,
icon: 'dc-icon-zifangguanli',
isCache: 1,
visible: 0,
sort: '1',
createTime: '2024-06-19 17:32:29',
modifyTime: '2024-07-15 15:45:58',
tag: null,
childList: [
{
id: 38,
resourceName: '首页商品',
resourceType: 1,
resourceCode: null,
path: '/goods/home-goods/index',
pid: 37,
resourceDesc: null,
tenantId: 2,
icon: '',
isCache: 1,
visible: 0,
sort: '1',
createTime: '2024-06-19 17:33:29',
modifyTime: '2024-06-19 17:56:01',
tag: null,
childList: []
},
{
id: 39,
resourceName: '商品管理',
resourceType: 1,
resourceCode: '',
path: '/goods/commodity/index',
pid: 37,
resourceDesc: null,
tenantId: 2,
icon: '',
isCache: 1,
visible: 0,
sort: '2',
createTime: '2024-06-19 17:35:07',
modifyTime: '2024-06-20 10:45:04',
tag: null,
childList: []
},
{
id: 126,
resourceName: '商品类目管理',
resourceType: 1,
resourceCode: null,
path: '/goods/category/index',
pid: 37,
resourceDesc: null,
tenantId: 2,
icon: '',
isCache: 1,
visible: 0,
sort: '3',
createTime: '2025-06-20 09:52:12',
modifyTime: '2025-06-20 09:53:53',
tag: null,
childList: []
}
/* {
id: 127,
resourceName: '锡商流程切换',
resourceType: 1,
resourceCode: null,
path: '/supplier/xsSwitch/index',
pid: 37,
resourceDesc: null,
tenantId: 2,
icon: '',
isCache: 1,
visible: 0,
sort: '4',
createTime: '2025-06-20 09:53:14',
modifyTime: '2025-06-20 09:53:14',
tag: null,
childList: []
} */
]
},
{
id: 40,
resourceName: '资源管理',
resourceType: 0,
resourceCode: '',
path: '/resource',
pid: 0,
resourceDesc: null,
tenantId: 2,
icon: 'dc-icon-xieyiguanli',
isCache: 1,
visible: 0,
sort: '2',
createTime: '2024-06-19 17:36:04',
modifyTime: '2024-07-15 15:46:07',
tag: null,
childList: [
{
id: 41,
resourceName: '资源列表',
resourceType: 1,
resourceCode: '',
path: '/resource/list/index',
pid: 40,
resourceDesc: null,
tenantId: 2,
icon: '',
isCache: 1,
visible: 0,
sort: '1',
createTime: '2024-06-19 17:36:29',
modifyTime: '2024-06-20 10:46:13',
tag: null,
childList: []
}
/* {
id: 42,
resourceName: '协议模板',
resourceType: 1,
resourceCode: '',
path: '/protocol/template/index',
pid: 40,
resourceDesc: null,
tenantId: 2,
icon: '',
isCache: 1,
visible: 0,
sort: '2',
createTime: '2024-06-19 17:40:43',
modifyTime: '2024-06-20 10:47:03',
tag: null,
childList: []
}
]
},
{
id: 43,
resourceName: '客户管理',
resourceType: 0,
resourceCode: null,
path: '/customer',
pid: 0,
resourceDesc: null,
tenantId: 2,
icon: 'dc-icon-kehuguanli1',
isCache: 1,
visible: 0,
sort: '3',
createTime: '2024-06-20 10:34:58',
modifyTime: '2024-07-15 16:23:26',
tag: null,
childList: [
{
id: 44,
resourceName: '客户信息查询',
resourceType: 1,
resourceCode: null,
path: '/customer/userInfo/index',
pid: 43,
resourceDesc: null,
tenantId: 2,
icon: '',
isCache: 1,
visible: 0,
sort: '1',
createTime: '2024-06-20 10:36:08',
modifyTime: '2024-09-10 16:17:41',
tag: null,
childList: []
},
{
id: 45,
resourceName: '客户详情',
resourceType: 1,
resourceCode: null,
path: '/customer/userInfo/detail/index',
pid: 43,
resourceDesc: null,
tenantId: 2,
icon: '',
isCache: 1,
visible: 1,
sort: '2',
createTime: '2024-06-21 16:55:54',
modifyTime: '2024-06-24 17:10:34',
tag: null,
childList: []
},
{
id: 55,
resourceName: '授信记录',
resourceType: 1,
resourceCode: null,
path: '/customer/creditRecord/index',
pid: 43,
resourceDesc: null,
tenantId: 2,
icon: '',
isCache: 1,
visible: 0,
sort: '3',
createTime: '2024-06-24 17:12:56',
modifyTime: '2024-09-10 16:17:44',
tag: null,
childList: []
},
{
id: 56,
resourceName: '借款记录',
resourceType: 1,
resourceCode: null,
path: '/customer/borrowRecord/index',
pid: 43,
resourceDesc: null,
tenantId: 2,
icon: '',
isCache: 1,
visible: 0,
sort: '4',
createTime: '2024-06-24 17:13:57',
modifyTime: '2024-07-01 15:29:51',
tag: null,
childList: []
},
{
id: 57,
resourceName: '借款详情',
resourceType: 1,
resourceCode: null,
path: '/customer/borrowRecord/detail/index',
pid: 43,
resourceDesc: null,
tenantId: 2,
icon: '',
isCache: 0,
visible: 1,
sort: '5',
createTime: '2024-06-24 17:14:59',
modifyTime: '2024-07-01 15:10:03',
tag: null,
childList: []
},
{
id: 58,
resourceName: '还款记录',
resourceType: 1,
resourceCode: null,
path: '/customer/repayRecord/index',
pid: 43,
resourceDesc: null,
tenantId: 2,
icon: '',
isCache: 1,
visible: 0,
sort: '6',
createTime: '2024-06-24 17:15:23',
modifyTime: '2024-06-25 14:21:03',
tag: null,
childList: []
},
{
id: 59,
resourceName: '意见反馈',
resourceType: 1,
resourceCode: null,
path: '/customer/feedback/index',
pid: 43,
resourceDesc: null,
tenantId: 2,
icon: '',
isCache: 1,
visible: 0,
sort: '7',
createTime: '2024-06-24 17:15:46',
modifyTime: '2024-06-24 17:15:46',
tag: null,
childList: []
},
{
id: 92,
resourceName: '提前结清白名单',
resourceType: 1,
resourceCode: null,
path: '/customer/payInAdvance/index',
pid: 43,
resourceDesc: null,
tenantId: 2,
icon: '',
isCache: 1,
visible: 0,
sort: '8',
createTime: '2024-11-13 09:45:55',
modifyTime: '2024-11-13 09:46:09',
tag: null,
childList: []
},
{
id: 93,
resourceName: '开具结清证明',
resourceType: 1,
resourceCode: null,
path: '/customer/ProofOfSettlement/index',
pid: 43,
resourceDesc: null,
tenantId: 2,
icon: '',
isCache: 1,
visible: 0,
sort: '9',
createTime: '2024-11-13 09:48:40',
modifyTime: '2024-11-13 09:48:40',
tag: null,
childList: []
},
{
id: 115,
resourceName: '授信记录-广告',
resourceType: 1,
resourceCode: null,
path: '/customer/creditRecord-adv/index',
pid: 43,
resourceDesc: null,
tenantId: 2,
icon: '',
isCache: 1,
visible: 0,
sort: '10',
createTime: '2025-05-12 14:39:58',
modifyTime: '2025-05-23 11:02:52',
tag: null,
childList: []
},
{
id: 122,
resourceName: '借款详情-广告',
resourceType: 1,
resourceCode: null,
path: '/customer/borrowRecord-adv/detail/index',
pid: 43,
resourceDesc: null,
tenantId: 2,
icon: '',
isCache: 1,
visible: 1,
sort: '11',
createTime: '2025-05-15 11:08:26',
modifyTime: '2025-05-15 11:40:29',
tag: null,
childList: []
},
{
id: 116,
resourceName: '借款记录-广告',
resourceType: 1,
resourceCode: null,
path: '/customer/borrowRecord-adv/index',
pid: 43,
resourceDesc: null,
tenantId: 2,
icon: '',
isCache: 1,
visible: 0,
sort: '12',
createTime: '2025-05-12 14:40:34',
modifyTime: '2025-06-12 18:53:17',
tag: null,
childList: []
},
{
id: 117,
resourceName: '还款记录-广告',
resourceType: 1,
resourceCode: null,
path: '/customer/repayRecord-adv/index',
pid: 43,
resourceDesc: null,
tenantId: 2,
icon: '',
isCache: 1,
visible: 0,
sort: '13',
createTime: '2025-05-12 14:41:27',
modifyTime: '2025-06-12 18:53:29',
tag: null,
childList: []
},
{
id: 124,
resourceName: '注销管理',
resourceType: 1,
resourceCode: null,
path: '/customer/logout/index',
pid: 43,
resourceDesc: null,
tenantId: 2,
icon: '',
isCache: 1,
visible: 0,
sort: '14',
createTime: '2025-06-10 09:41:48',
modifyTime: '2025-06-12 18:53:42',
tag: null,
childList: []
},
{
id: 125,
resourceName: '银行卡管理',
resourceType: 1,
resourceCode: null,
path: '/customer/bankCard/index',
pid: 43,
resourceDesc: null,
tenantId: 2,
icon: '',
isCache: 1,
visible: 0,
sort: '15',
createTime: '2025-06-10 09:42:32',
modifyTime: '2025-06-12 18:54:01',
tag: null,
childList: []
}*/
]
}
/* {
id: 60,
resourceName: '渠道管理',
resourceType: 0,
resourceCode: null,
path: '/channel',
pid: 0,
resourceDesc: null,
tenantId: 2,
icon: 'dc-icon-qudaoguanli',
isCache: 1,
visible: 0,
sort: '4',
createTime: '2024-09-10 17:30:05',
modifyTime: '2024-09-10 17:31:17',
tag: null,
childList: [
{
id: 61,
resourceName: '渠道配置',
resourceType: 1,
resourceCode: null,
path: '/channel/config/index',
pid: 60,
resourceDesc: null,
tenantId: 2,
icon: '',
isCache: 1,
visible: 0,
sort: '1',
createTime: '2024-09-10 17:31:04',
modifyTime: '2024-09-10 17:31:04',
tag: null,
childList: []
}
]
},
{
id: 110,
resourceName: '产品管理',
resourceType: 0,
resourceCode: null,
path: '/product',
pid: 0,
resourceDesc: null,
tenantId: 2,
icon: '',
isCache: 1,
visible: 0,
sort: '5',
createTime: '2025-05-12 14:29:23',
modifyTime: '2025-05-12 14:29:23',
tag: null,
childList: [
{
id: 111,
resourceName: '产品管理',
resourceType: 1,
resourceCode: null,
path: '/product/production/index',
pid: 110,
resourceDesc: null,
tenantId: 2,
icon: '',
isCache: 1,
visible: 0,
sort: '1',
createTime: '2025-05-12 14:30:22',
modifyTime: '2025-05-12 14:37:00',
tag: null,
childList: []
},
{
id: 112,
resourceName: '进件计划',
resourceType: 1,
resourceCode: null,
path: '/product/incoming-plan/index',
pid: 110,
resourceDesc: null,
tenantId: 2,
icon: '',
isCache: 1,
visible: 0,
sort: '2',
createTime: '2025-05-12 14:32:35',
modifyTime: '2025-05-12 14:33:40',
tag: null,
childList: []
},
{
id: 113,
resourceName: '前筛规则',
resourceType: 1,
resourceCode: null,
path: '/product/filtrate-rule/index',
pid: 110,
resourceDesc: null,
tenantId: 2,
icon: '',
isCache: 1,
visible: 0,
sort: '3',
createTime: '2025-05-12 14:34:55',
modifyTime: '2025-05-12 14:34:55',
tag: null,
childList: []
},
{
id: 114,
resourceName: '展示位配置',
resourceType: 1,
resourceCode: null,
path: '/product/show-location-config/index',
pid: 110,
resourceDesc: null,
tenantId: 2,
icon: '',
isCache: 1,
visible: 0,
sort: '4',
createTime: '2025-05-12 14:36:08',
modifyTime: '2025-05-12 14:36:08',
tag: null,
childList: []
}
]
},
{
id: 118,
resourceName: '放款管理',
resourceType: 0,
resourceCode: null,
path: '/loan',
pid: 0,
resourceDesc: null,
tenantId: 2,
icon: '',
isCache: 1,
visible: 0,
sort: '6',
createTime: '2025-05-14 10:38:33',
modifyTime: '2025-05-14 10:38:33',
tag: null,
childList: [
{
id: 119,
resourceName: '放款计划管理(资方)',
resourceType: 1,
resourceCode: null,
path: '/loan/plan-manage/supplier',
pid: 118,
resourceDesc: null,
tenantId: 2,
icon: '',
isCache: 1,
visible: 0,
sort: '1',
createTime: '2025-05-14 10:39:52',
modifyTime: '2025-05-21 17:19:09',
tag: null,
childList: []
},
{
id: 123,
resourceName: '放款计划管理(渠道)',
resourceType: 1,
resourceCode: null,
path: '/loan/plan-manage/channel',
pid: 118,
resourceDesc: null,
tenantId: 2,
icon: '',
isCache: 1,
visible: 0,
sort: '2',
createTime: '2025-05-21 17:18:43',
modifyTime: '2025-05-21 17:19:23',
tag: null,
childList: []
},
{
id: 121,
resourceName: '待放款订单',
resourceType: 1,
resourceCode: null,
path: '/loan/wait-loan/index',
pid: 118,
resourceDesc: null,
tenantId: 2,
icon: '',
isCache: 1,
visible: 0,
sort: '3',
createTime: '2025-05-14 11:12:05',
modifyTime: '2025-05-14 11:12:05',
tag: null,
childList: []
}
]
} */
]

View File

@ -20,6 +20,11 @@ export const constantRoutes: Array<RouteRecordRaw> = [
meta: { title: '错误页', hidden: true }
}
]
},
{
path: '/login',
name: 'login',
component: () => import('@/views/login/index.vue')
}
]

View File

@ -3,6 +3,7 @@ import type { UserState } from './types'
import { resetRouter } from '@/router'
import api from '@/api'
const { apiGetUserRoleInfo, apiLogout } = api.login
import menuList from '@/config/menuList.ts'
const useUserStore = defineStore('user', {
state: (): UserState => {
@ -28,7 +29,8 @@ const useUserStore = defineStore('user', {
// 获取用户信息(昵称、头像、角色集合、权限集合)
getUserRoleInfo() {
return new Promise((resolve) => {
apiGetUserRoleInfo.get!({ tenantCode: 'loan_system' }).then((res: any) => {
resolve(menuList)
/* apiGetUserRoleInfo.get!({ tenantCode: 'loan_system' }).then((res: any) => {
const {
userInfo: { userPhone, userNickName, tenantId, id },
menuResourceList,
@ -44,7 +46,7 @@ const useUserStore = defineStore('user', {
...(buttonResourceList ? buttonResourceList.map((item: any) => item.resourceCode) : [])
)
resolve(menuResourceList)
})
}) */
})
},
// 退出登录

View File

@ -8,7 +8,7 @@ import useStore from '@/stores'
// 创建 axios 实例
const service = axios.create({
baseURL: '/portal',
baseURL: '/api-interface/mm',
timeout: 50000,
headers: {}
})

View File

@ -1,10 +1,5 @@
<script setup>
import { ElMessage } from 'element-plus'
import { Encrypt } from '@/utils/crypto'
import { getCurrentTime } from '@/utils/config'
import useStore from '@/stores'
import { apiGetImgCode, apiGetSmsCode } from '@/api/login'
import DialogPassword from '@/components/DialogPassword/index.vue'
const { user } = useStore()
const router = useRouter()
@ -12,93 +7,13 @@ const router = useRouter()
// el-formref
const loginFormRef = ref(null)
const loginData = reactive({
userPhoneEn: '',
password: '',
imageCode: '',
uuid: '',
smsCode: ''
username: '',
password: ''
})
const loginRules = reactive({
userPhoneEn: [
{ required: true, message: '请输入手机号', trigger: 'blur' },
{
pattern: /^1[3|4|5|6|7|8|9][0-9]\d{8}$/,
message: '请输入正确的手机号码',
trigger: 'blur'
}
],
imageCode: [
{ required: true, message: '请输入图像验证码', trigger: 'blur' },
{ min: 4, message: '图像验证码不能少于4位', trigger: 'blur' }
],
password: [
{ required: true, message: '请输入密码', trigger: 'blur' },
{ min: 8, message: '密码不能少于8位', trigger: 'blur' },
{ max: 16, message: '密码不能超过16位', trigger: 'blur' }
],
smsCode: [
{ required: true, message: '请输入短信验证码', trigger: 'blur' },
{ min: 6, message: '短信验证码不能少于6位', trigger: 'blur' }
]
username: [{ required: true, message: '请输入用户名', trigger: 'blur' }],
password: [{ required: true, message: '请输入密码', trigger: 'blur' }]
})
const imageCodeUrl = ref('') //
const hasSendMsg = ref(false) //
const time = ref(0) //
const dialogPasswordVisible = ref(false)
//
const handleGetImgCode = () => {
apiGetImgCode().then((res) => {
if (res.code === 200) {
imageCodeUrl.value = `data:image/gif;base64,${res.data.img}`
loginData.uuid = res.data.uuid
}
})
}
handleGetImgCode()
//
const timer = ref()
const handleGetSmsCode = () => {
if (hasSendMsg.value) return
const emptyData = {
userPhoneEn: loginData.userPhoneEn,
password: loginData.password,
imageCode: loginData.imageCode,
uuid: loginData.uuid
}
if (hasEmptyValue(emptyData)) {
return ElMessage.error('请输入对应信息')
}
apiGetSmsCode({
userPhoneEn: loginData.userPhoneEn,
password: Encrypt(loginData.password),
imageCode: loginData.imageCode,
uuid: loginData.uuid
}).then((res) => {
if (res.code === 200) {
hasSendMsg.value = true
time.value = 60
timeCb()
} else {
ElMessage.error(res.msg)
setTimeout(() => {
handleGetImgCode()
loginData.imageCode = ''
}, 1000)
}
})
//
const timeCb = () => {
clearTimeout(timer)
time.value--
if (time.value < 1) {
return (hasSendMsg.value = false)
}
timer.value = setTimeout(timeCb, 1000)
}
}
//
const handleLogin = () => {
@ -116,29 +31,11 @@ const handleLogin = () => {
}
})
}
//
const hasEmptyValue = (obj) => {
for (let key in obj) {
if (obj[key] == null || obj[key] === '') {
return true
}
}
return false
}
//
const currentDate = ref()
setInterval(() => {
currentDate.value = getCurrentTime()
})
</script>
<template>
<div id="login">
<el-card class="login_elCard">
<h2>东成工作台</h2>
<h3>{{ currentDate }}</h3>
<el-form
:model="loginData"
:rules="loginRules"
@ -147,9 +44,9 @@ setInterval(() => {
@keyup.enter="handleLogin"
class="login_form"
>
<el-form-item label="手机号码" prop="userPhoneEn">
<el-form-item label="手机号码" prop="username">
<el-input
v-model="loginData.userPhoneEn"
v-model="loginData.username"
placeholder="请输入手机号码"
type="text"
maxlength="11"
@ -167,45 +64,11 @@ setInterval(() => {
class="login_form__input"
/>
</el-form-item>
<el-form-item label="图像验证码" prop="imageCode">
<el-input
v-model="loginData.imageCode"
placeholder="请输入图像验证码"
type="text"
maxlength="4"
class="login_form__input login_form__img-code"
>
<template #append>
<img class="login_form__input-img" @click="handleGetImgCode" :src="imageCodeUrl" />
</template>
</el-input>
</el-form-item>
<el-form-item label="短信验证码" prop="smsCode">
<el-input
v-model="loginData.smsCode"
placeholder="请输入短信验证码"
type="text"
maxlength="6"
class="login_form__input"
>
<template #append>
<span class="cursor-pointer" @click="handleGetSmsCode">
{{ hasSendMsg ? time + 's后重发' : '发送验证码' }}
</span>
</template>
</el-input>
</el-form-item>
</el-form>
<div class="login_submit_btn">
<el-button @click="handleLogin" type="primary">登录</el-button>
</div>
</el-card>
<dialog-password
ref="dialogPasswordRef"
v-model:dialogPasswordVisible="dialogPasswordVisible"
:loginData="loginData"
:type="'init'"
/>
</div>
</template>

View File

@ -0,0 +1,128 @@
<template>
<div id="category-tree" class="p-2 bg-white">
<p>类目展示</p>
<el-tree
style="max-width: 600px"
:data="dataSource"
node-key="id"
draggable
default-expand-all
:expand-on-click-node="false"
@node-drag-start="handleDragStart"
@node-drag-enter="handleDragEnter"
@node-drag-leave="handleDragLeave"
@node-drag-over="handleDragOver"
@node-drag-end="handleDragEnd"
@node-drop="handleDrop"
>
<template #default="{ node, data }">
<div class="category-tree-node">
<span v-if="curId !== data.id">{{ data.label }}</span>
<el-input
ref="inputRef"
v-else
v-model="data.label2"
size="small"
class="w-40"
@keyup.enter="handleInputConfirm(data)"
@blur="handleInputCancel(node, data)"
/>
<div>
<el-button type="primary" link @click="edit(data)" size="small">编辑 </el-button>
<el-button type="primary" link @click="append(data)" size="small"> 添加 </el-button>
<el-button type="danger" size="small" link @click="remove(node, data)">
删除
</el-button>
</div>
</div>
</template>
</el-tree>
</div>
</template>
<script lang="ts" setup>
import { ElButton } from 'element-plus'
import type { RenderContentContext } from 'element-plus'
import { dataSource } from './mock'
import {
handleDragStart,
handleDragEnter,
handleDragOver,
handleDragLeave,
handleDragEnd,
handleDrop
} from './use-drag'
interface Tree {
id: number
label: string
children?: Tree[]
}
type Node = RenderContentContext['node']
type Data = RenderContentContext['data']
const curId = ref(NaN)
const inputRef = ref()
const edit = (data: Data) => {
data.label2 = data.label
curId.value = data.id
nextTick(() => {
inputRef.value.focus()
})
}
//
const handleInputConfirm = (data: any) => {
if (curId.value === Infinity) {
//
} else {
//
}
data.label = data.label2
data.label2 = ''
curId.value = NaN
}
//
const handleInputCancel = (node: Node, data: Data) => {
if (data.id === Infinity) {
remove(node, data)
}
curId.value = NaN
}
const append = (data: Data) => {
curId.value = Infinity
const newChild = { id: curId.value, label2: 'test', children: [] }
if (!data.children) {
data.children = []
}
data.children.push(newChild)
dataSource.value = [...dataSource.value]
nextTick(() => {
inputRef.value.focus()
})
}
const remove = (node: Node, data: Data) => {
const parent = node.parent
const children: Tree[] = parent?.data.children || parent?.data
const index = children.findIndex((d) => d.id === data.id)
children.splice(index, 1)
dataSource.value = [...dataSource.value]
}
</script>
<style lang="scss" scoped>
#category-tree {
.category-tree-node {
flex: 1;
display: flex;
align-items: center;
justify-content: space-between;
font-size: 14px;
padding-right: 8px;
}
}
</style>

View File

@ -0,0 +1,56 @@
interface Tree {
id: number
label: string
children?: Tree[]
}
export const dataSource = ref<Tree[]>([
{
id: 1,
label: 'Level one 1',
children: [
{
id: 4,
label: 'Level two 1-1',
children: [
{
id: 9,
label: 'Level three 1-1-1'
},
{
id: 10,
label: 'Level three 1-1-2'
}
]
}
]
},
{
id: 2,
label: 'Level one 2',
children: [
{
id: 5,
label: 'Level two 2-1'
},
{
id: 6,
label: 'Level two 2-2'
}
]
},
{
id: 3,
label: 'Level one 3',
children: [
{
id: 7,
label: 'Level two 3-1'
},
{
id: 8,
label: 'Level two 3-2'
}
]
}
])

View File

@ -0,0 +1,39 @@
import type { DragEvents } from 'element-plus/es/components/tree/src/model/useDragNode'
import type { NodeDropType, RenderContentContext } from 'element-plus'
type Node = RenderContentContext['node']
// 开始拖拽
export const handleDragStart = (node: Node, ev: DragEvents) => {
console.log('drag start', node)
}
// 拖拽进入其他节点时触发的事件
export const handleDragEnter = (draggingNode: Node, dropNode: Node, ev: DragEvents) => {
console.log('tree drag enter:', dropNode.label)
}
// 拖拽离开某个节点时触发的事件
export const handleDragLeave = (draggingNode: Node, dropNode: Node, ev: DragEvents) => {
console.log('tree drag leave:', dropNode.label)
}
// 在拖拽节点时触发的事件(类似浏览器的 mouseover 事件)
export const handleDragOver = (draggingNode: Node, dropNode: Node, ev: DragEvents) => {
console.log('tree drag over:', dropNode.label)
}
// 拖拽结束时(可能未成功)触发的事件
export const handleDragEnd = (
draggingNode: Node,
dropNode: Node,
dropType: NodeDropType,
ev: DragEvents
) => {
console.log('tree drag end:', dropNode && dropNode.label, dropType)
}
// 拖拽成功完成时触发的事件
export const handleDrop = (
draggingNode: Node,
dropNode: Node,
dropType: NodeDropType,
ev: DragEvents
) => {
console.log('tree drop:', dropNode.label, dropType)
}

1
types/global.d.ts vendored
View File

@ -3,7 +3,6 @@ import totalApiConfig from '@/api'
declare global {
type api = typeof totalApiConfig
type abc = 123
type Recordable<T = any> = Record<string, T>
interface Array {

View File

@ -15,6 +15,10 @@ export default defineConfig({
'/portal': {
target: 'http://127.0.0.1:4523/m1/6997834-6716269-default',
changeOrigin: true
},
'/api-interface/mm': {
target: 'https://api.1024api.com',
changeOrigin: true
}
},
host: '0.0.0.0',