mirror of
https://github.com/continew-org/continew-admin-ui.git
synced 2025-11-11 12:57:10 +08:00
refactor: 更换 ESLint 配置为 @antfu/eslint-config
This commit is contained in:
@@ -23,13 +23,12 @@ import Icon500 from '@/components/icons/Icon500.vue'
|
||||
|
||||
defineOptions({ name: 'ErrorPage' })
|
||||
|
||||
interface Props {
|
||||
code: number
|
||||
}
|
||||
const props = withDefaults(defineProps<Props>(), {
|
||||
code: 403
|
||||
})
|
||||
|
||||
interface Props {
|
||||
code: number
|
||||
}
|
||||
const IconMap: Record<number, Component> = {
|
||||
403: Icon403,
|
||||
404: Icon404,
|
||||
|
||||
@@ -9,5 +9,5 @@ const router = useRouter()
|
||||
const { params, query } = route
|
||||
const { path } = params
|
||||
|
||||
router.replace({ path: '/' + path, query })
|
||||
router.replace({ path: `/${path}`, query })
|
||||
</script>
|
||||
|
||||
@@ -13,11 +13,28 @@
|
||||
</template>
|
||||
|
||||
<script lang="ts" setup>
|
||||
import { listDashboardAccessTrend, type DashboardAccessTrendResp } from '@/apis'
|
||||
import VCharts from 'vue-echarts'
|
||||
import { graphic } from 'echarts'
|
||||
import { type DashboardAccessTrendResp, listDashboardAccessTrend } from '@/apis'
|
||||
import { useChart } from '@/hooks'
|
||||
|
||||
// 提示框
|
||||
const tooltipItemsHtmlString = (items) => {
|
||||
return items
|
||||
.map(
|
||||
(el) => `<div class="content-panel">
|
||||
<p>
|
||||
<span style="background-color: ${el.color}" class="tooltip-item-icon"></span>
|
||||
<span>${el.seriesName}</span>
|
||||
</p>
|
||||
<span class="tooltip-value">
|
||||
${el.value}
|
||||
</span>
|
||||
</div>`
|
||||
)
|
||||
.join('')
|
||||
}
|
||||
|
||||
const xData = ref<string[]>([])
|
||||
const pvStatisticsData = ref<number[]>([])
|
||||
const ipStatisticsData = ref<number[]>([])
|
||||
@@ -196,23 +213,6 @@ const onChange = (days: number) => {
|
||||
getChartData(days)
|
||||
}
|
||||
|
||||
// 提示框
|
||||
const tooltipItemsHtmlString = (items) => {
|
||||
return items
|
||||
.map(
|
||||
(el) => `<div class="content-panel">
|
||||
<p>
|
||||
<span style="background-color: ${el.color}" class="tooltip-item-icon"></span>
|
||||
<span>${el.seriesName}</span>
|
||||
</p>
|
||||
<span class="tooltip-value">
|
||||
${el.value}
|
||||
</span>
|
||||
</div>`
|
||||
)
|
||||
.join('')
|
||||
}
|
||||
|
||||
onMounted(() => {
|
||||
getChartData(30)
|
||||
})
|
||||
|
||||
@@ -2,7 +2,7 @@
|
||||
<a-card title="快捷操作" :bordered="false" size="medium" class="card gi_card_title">
|
||||
<a-card-grid v-for="(item, index) in list" :key="item.name" class="card-grid-item" :style="{ width: '33.33%' }">
|
||||
<a-card :bordered="false" hoverable>
|
||||
<a-row justify="center" align="center" :class="'animated-fade-up-' + (index + 1)">
|
||||
<a-row justify="center" align="center" :class="`animated-fade-up-${index + 1}`">
|
||||
<a-space direction="vertical" align="center" class="wrapper" @click="router.replace({ path: item.path })">
|
||||
<component :is="item.icon" :size="30" class="icon"></component>
|
||||
<a-typography-text class="text">{{ item.name }}</a-typography-text>
|
||||
|
||||
@@ -7,7 +7,7 @@
|
||||
v-for="(item, index) in list"
|
||||
:key="index"
|
||||
align="right"
|
||||
:class="'animated-fade-up-' + index"
|
||||
:class="`animated-fade-up-${index}`"
|
||||
style="overflow: hidden"
|
||||
>
|
||||
<template #content>
|
||||
|
||||
@@ -8,7 +8,7 @@
|
||||
v-for="(item, index) in dataList"
|
||||
:key="index"
|
||||
align="right"
|
||||
:class="'animated-fade-up-' + index"
|
||||
:class="`animated-fade-up-${index}`"
|
||||
style="overflow: hidden"
|
||||
>
|
||||
<template #content>
|
||||
@@ -26,7 +26,7 @@
|
||||
</template>
|
||||
|
||||
<script setup lang="ts">
|
||||
import { listDashboardNotice, type DashboardNoticeResp } from '@/apis'
|
||||
import { type DashboardNoticeResp, listDashboardNotice } from '@/apis'
|
||||
import { useDict } from '@/hooks/app'
|
||||
import NoticeDetailModal from '@/views/system/notice/NoticeDetailModal.vue'
|
||||
|
||||
|
||||
@@ -3,7 +3,7 @@
|
||||
<a-row align="stretch">
|
||||
<a-col v-for="(item, index) in list" :key="item.name" :xs="12" :sm="8" :md="8">
|
||||
<a-card-grid class="w-full h-full">
|
||||
<a-card :bordered="false" hoverable :class="'animated-fade-up-' + index">
|
||||
<a-card :bordered="false" hoverable :class="`animated-fade-up-${index}`">
|
||||
<a :href="item.url" target="_blank">
|
||||
<section class="item">
|
||||
<div class="item__header">
|
||||
|
||||
@@ -26,10 +26,10 @@
|
||||
|
||||
<script setup lang="ts">
|
||||
import NowTime from './NowTime/index.vue'
|
||||
import SupportCard from './SupportCard.vue'
|
||||
import { useDevice } from '@/hooks'
|
||||
import { useUserStore } from '@/stores'
|
||||
import { goodTimeText } from '@/utils'
|
||||
import SupportCard from './SupportCard.vue'
|
||||
|
||||
const { isDesktop } = useDevice()
|
||||
const userStore = useUserStore()
|
||||
|
||||
@@ -31,19 +31,17 @@
|
||||
</a-form-item>
|
||||
<a-form-item>
|
||||
<a-space direction="vertical" fill class="w-full">
|
||||
<a-button class="btn" type="primary" :loading="loading" html-type="submit" size="large" long
|
||||
>立即登录
|
||||
</a-button>
|
||||
<a-button class="btn" type="primary" :loading="loading" html-type="submit" size="large" long>立即登录</a-button>
|
||||
</a-space>
|
||||
</a-form-item>
|
||||
</a-form>
|
||||
</template>
|
||||
|
||||
<script setup lang="ts">
|
||||
import { getImageCaptcha } from '@/apis'
|
||||
import { Message, type FormInstance, Modal } from '@arco-design/web-vue'
|
||||
import { useUserStore } from '@/stores'
|
||||
import { type FormInstance, Message } from '@arco-design/web-vue'
|
||||
import { useStorage } from '@vueuse/core'
|
||||
import { getImageCaptcha } from '@/apis'
|
||||
import { useUserStore } from '@/stores'
|
||||
import { encryptByRsa } from '@/utils/encrypt'
|
||||
|
||||
const loginConfig = useStorage('login-config', {
|
||||
@@ -62,13 +60,46 @@ const form = reactive({
|
||||
uuid: '',
|
||||
expired: false
|
||||
})
|
||||
|
||||
const rules: FormInstance['rules'] = {
|
||||
username: [{ required: true, message: '请输入用户名' }],
|
||||
password: [{ required: true, message: '请输入密码' }],
|
||||
captcha: [{ required: true, message: '请输入验证码' }]
|
||||
}
|
||||
|
||||
// 验证码过期定时器
|
||||
let timer
|
||||
const startTimer = (expireTime: number) => {
|
||||
if (timer) {
|
||||
clearTimeout(timer)
|
||||
}
|
||||
const remainingTime = expireTime - Date.now()
|
||||
if (remainingTime <= 0) {
|
||||
form.expired = true
|
||||
return
|
||||
}
|
||||
timer = setTimeout(() => {
|
||||
form.expired = true
|
||||
}, remainingTime)
|
||||
}
|
||||
// 组件销毁时清理定时器
|
||||
onBeforeUnmount(() => {
|
||||
if (timer) {
|
||||
clearTimeout(timer)
|
||||
}
|
||||
})
|
||||
|
||||
const captchaImgBase64 = ref()
|
||||
// 获取验证码
|
||||
const getCaptcha = () => {
|
||||
getImageCaptcha().then((res) => {
|
||||
const { uuid, img, expireTime } = res.data
|
||||
form.uuid = uuid
|
||||
captchaImgBase64.value = img
|
||||
form.expired = false
|
||||
startTimer(expireTime)
|
||||
})
|
||||
}
|
||||
|
||||
const userStore = useUserStore()
|
||||
const router = useRouter()
|
||||
const loading = ref(false)
|
||||
@@ -102,40 +133,6 @@ const handleLogin = async () => {
|
||||
}
|
||||
}
|
||||
|
||||
const captchaImgBase64 = ref()
|
||||
// 获取验证码
|
||||
const getCaptcha = () => {
|
||||
getImageCaptcha().then((res) => {
|
||||
const { uuid, img, expireTime } = res.data
|
||||
form.uuid = uuid
|
||||
captchaImgBase64.value = img
|
||||
form.expired = false
|
||||
startTimer(expireTime)
|
||||
})
|
||||
}
|
||||
|
||||
// 验证码过期定时器
|
||||
let timer
|
||||
const startTimer = (expireTime: number) => {
|
||||
if (timer) {
|
||||
clearTimeout(timer)
|
||||
}
|
||||
const remainingTime = expireTime - Date.now()
|
||||
if (remainingTime <= 0) {
|
||||
form.expired = true
|
||||
return
|
||||
}
|
||||
timer = setTimeout(() => {
|
||||
form.expired = true
|
||||
}, remainingTime)
|
||||
}
|
||||
// 组件销毁时清理定时器
|
||||
onBeforeUnmount(() => {
|
||||
if (timer) {
|
||||
clearTimeout(timer)
|
||||
}
|
||||
})
|
||||
|
||||
onMounted(() => {
|
||||
getCaptcha()
|
||||
})
|
||||
|
||||
@@ -25,8 +25,7 @@
|
||||
</a-form-item>
|
||||
<a-form-item>
|
||||
<a-space direction="vertical" fill class="w-full">
|
||||
<a-button disabled class="btn" type="primary" :loading="loading" html-type="submit" size="large" long
|
||||
>立即登录</a-button
|
||||
<a-button disabled class="btn" type="primary" :loading="loading" html-type="submit" size="large" long>立即登录</a-button
|
||||
>
|
||||
</a-space>
|
||||
</a-form-item>
|
||||
@@ -35,7 +34,7 @@
|
||||
|
||||
<script setup lang="ts">
|
||||
// import { getEmailCaptcha } from '@/apis'
|
||||
import { Message, type FormInstance } from '@arco-design/web-vue'
|
||||
import { type FormInstance, Message } from '@arco-design/web-vue'
|
||||
import { useUserStore } from '@/stores'
|
||||
import * as Regexp from '@/utils/regexp'
|
||||
|
||||
|
||||
@@ -25,8 +25,7 @@
|
||||
</a-form-item>
|
||||
<a-form-item>
|
||||
<a-space direction="vertical" fill class="w-full">
|
||||
<a-button disabled class="btn" type="primary" :loading="loading" html-type="submit" size="large" long
|
||||
>立即登录</a-button
|
||||
<a-button disabled class="btn" type="primary" :loading="loading" html-type="submit" size="large" long>立即登录</a-button
|
||||
>
|
||||
</a-space>
|
||||
</a-form-item>
|
||||
@@ -35,7 +34,7 @@
|
||||
|
||||
<script setup lang="ts">
|
||||
// import { getSmsCaptcha } from '@/apis'
|
||||
import { Message, type FormInstance } from '@arco-design/web-vue'
|
||||
import { type FormInstance, Message } from '@arco-design/web-vue'
|
||||
import { useUserStore } from '@/stores'
|
||||
import * as Regexp from '@/utils/regexp'
|
||||
|
||||
|
||||
@@ -89,11 +89,11 @@
|
||||
</template>
|
||||
|
||||
<script setup lang="ts">
|
||||
import { socialAuth } from '@/apis'
|
||||
import Background from './components/background/index.vue'
|
||||
import AccountLogin from './components/account/index.vue'
|
||||
import PhoneLogin from './components/phone/index.vue'
|
||||
import EmailLogin from './components/email/index.vue'
|
||||
import { socialAuth } from '@/apis'
|
||||
import { useAppStore } from '@/stores'
|
||||
import { useDevice } from '@/hooks'
|
||||
|
||||
|
||||
@@ -5,9 +5,9 @@
|
||||
</template>
|
||||
|
||||
<script setup lang="ts">
|
||||
import { bindSocialAccount } from '@/apis'
|
||||
import { Message } from '@arco-design/web-vue'
|
||||
import { useRoute, useRouter } from 'vue-router'
|
||||
import { bindSocialAccount } from '@/apis'
|
||||
import { isLogin } from '@/utils/auth'
|
||||
|
||||
const route = useRoute()
|
||||
|
||||
@@ -20,8 +20,8 @@ const route = useRoute()
|
||||
const router = useRouter()
|
||||
|
||||
const PaneMap: Record<string, Component> = {
|
||||
'1': LoginLog,
|
||||
'2': OperationLog
|
||||
1: LoginLog,
|
||||
2: OperationLog
|
||||
}
|
||||
|
||||
const activeKey = ref('1')
|
||||
|
||||
@@ -6,7 +6,7 @@
|
||||
:loading="loading"
|
||||
:scroll="{ x: '100%', y: '100%', minWidth: 1000 }"
|
||||
:pagination="pagination"
|
||||
:disabledTools="['size', 'setting']"
|
||||
:disabled-tools="['size', 'setting']"
|
||||
@filter-change="filterChange"
|
||||
@refresh="search"
|
||||
>
|
||||
@@ -45,14 +45,42 @@
|
||||
</template>
|
||||
|
||||
<script setup lang="ts">
|
||||
import { exportLoginLog, listLog, type LogQuery } from '@/apis'
|
||||
import dayjs from 'dayjs'
|
||||
import { type LogQuery, exportLoginLog, listLog } from '@/apis'
|
||||
import type { TableInstanceColumns } from '@/components/GiTable/type'
|
||||
import DateRangePicker from '@/components/DateRangePicker/index.vue'
|
||||
import { useTable, useDownload } from '@/hooks'
|
||||
import dayjs from 'dayjs'
|
||||
import { useDownload, useTable } from '@/hooks'
|
||||
|
||||
defineOptions({ name: 'LoginLog' })
|
||||
|
||||
const queryForm = reactive<LogQuery>({
|
||||
module: '登录',
|
||||
createTime: [
|
||||
dayjs().subtract(6, 'day').startOf('day').format('YYYY-MM-DD HH:mm:ss'),
|
||||
dayjs().endOf('day').format('YYYY-MM-DD HH:mm:ss')
|
||||
],
|
||||
sort: ['createTime,desc']
|
||||
})
|
||||
|
||||
const {
|
||||
tableData: dataList,
|
||||
loading,
|
||||
pagination,
|
||||
search
|
||||
} = useTable((p) => listLog({ ...queryForm, page: p.page, size: p.size }), { immediate: true })
|
||||
|
||||
// 重置
|
||||
const reset = () => {
|
||||
queryForm.ip = undefined
|
||||
queryForm.createUserString = undefined
|
||||
queryForm.createTime = [
|
||||
dayjs().subtract(6, 'day').startOf('day').format('YYYY-MM-DD HH:mm:ss'),
|
||||
dayjs().endOf('day').format('YYYY-MM-DD HH:mm:ss')
|
||||
]
|
||||
queryForm.status = undefined
|
||||
search()
|
||||
}
|
||||
|
||||
const columns: TableInstanceColumns[] = [
|
||||
{
|
||||
title: '序号',
|
||||
@@ -90,22 +118,6 @@ const columns: TableInstanceColumns[] = [
|
||||
{ title: '终端系统', dataIndex: 'os', ellipsis: true, tooltip: true }
|
||||
]
|
||||
|
||||
const queryForm = reactive<LogQuery>({
|
||||
module: '登录',
|
||||
createTime: [
|
||||
dayjs().subtract(6, 'day').startOf('day').format('YYYY-MM-DD HH:mm:ss'),
|
||||
dayjs().endOf('day').format('YYYY-MM-DD HH:mm:ss')
|
||||
],
|
||||
sort: ['createTime,desc']
|
||||
})
|
||||
|
||||
const {
|
||||
tableData: dataList,
|
||||
loading,
|
||||
pagination,
|
||||
search
|
||||
} = useTable((p) => listLog({ ...queryForm, page: p.page, size: p.size }), { immediate: true })
|
||||
|
||||
// 过滤查询
|
||||
const filterChange = (dataIndex, filteredValues) => {
|
||||
try {
|
||||
@@ -117,18 +129,6 @@ const filterChange = (dataIndex, filteredValues) => {
|
||||
}
|
||||
}
|
||||
|
||||
// 重置
|
||||
const reset = () => {
|
||||
queryForm.ip = undefined
|
||||
queryForm.createUserString = undefined
|
||||
queryForm.createTime = [
|
||||
dayjs().subtract(6, 'day').startOf('day').format('YYYY-MM-DD HH:mm:ss'),
|
||||
dayjs().endOf('day').format('YYYY-MM-DD HH:mm:ss')
|
||||
]
|
||||
queryForm.status = undefined
|
||||
search()
|
||||
}
|
||||
|
||||
// 导出
|
||||
const onExport = () => {
|
||||
useDownload(() => exportLoginLog(queryForm))
|
||||
|
||||
@@ -2,9 +2,7 @@
|
||||
<a-drawer v-model:visible="visible" title="日志详情" :width="720" :footer="false">
|
||||
<a-descriptions title="基本信息" :column="2" size="large" class="general-description">
|
||||
<a-descriptions-item label="日志 ID">{{ dataDetail?.id }}</a-descriptions-item>
|
||||
<a-descriptions-item label="Trace ID"
|
||||
>{{ dataDetail?.traceId }}<TextCopy :value="dataDetail?.traceId"
|
||||
/></a-descriptions-item>
|
||||
<a-descriptions-item label="Trace ID">{{ dataDetail?.traceId }}<TextCopy :value="dataDetail?.traceId" /></a-descriptions-item>
|
||||
<a-descriptions-item label="操作人">{{ dataDetail?.createUserString }}</a-descriptions-item>
|
||||
<a-descriptions-item label="操作时间">{{ dataDetail?.createTime }}</a-descriptions-item>
|
||||
<a-descriptions-item label="操作内容">{{ dataDetail?.description }}</a-descriptions-item>
|
||||
@@ -70,7 +68,7 @@
|
||||
</template>
|
||||
|
||||
<script lang="ts" setup>
|
||||
import { getLog, type LogDetailResp } from '@/apis'
|
||||
import { type LogDetailResp, getLog } from '@/apis'
|
||||
|
||||
const dataId = ref('')
|
||||
const dataDetail = ref<LogDetailResp>()
|
||||
|
||||
@@ -7,7 +7,7 @@
|
||||
:scroll="{ x: '100%', y: '100%', minWidth: 1000 }"
|
||||
:pagination="pagination"
|
||||
column-resizable
|
||||
:disabledTools="['size', 'setting']"
|
||||
:disabled-tools="['size', 'setting']"
|
||||
@filter-change="filterChange"
|
||||
@refresh="search"
|
||||
>
|
||||
@@ -56,15 +56,43 @@
|
||||
</template>
|
||||
|
||||
<script setup lang="ts">
|
||||
import { listLog, exportOperationLog, type LogResp, type LogQuery } from '@/apis'
|
||||
import dayjs from 'dayjs'
|
||||
import OperationLogDetailDrawer from './OperationLogDetailDrawer.vue'
|
||||
import { type LogQuery, type LogResp, exportOperationLog, listLog } from '@/apis'
|
||||
import type { TableInstanceColumns } from '@/components/GiTable/type'
|
||||
import DateRangePicker from '@/components/DateRangePicker/index.vue'
|
||||
import { useTable, useDownload } from '@/hooks'
|
||||
import dayjs from 'dayjs'
|
||||
import { useDownload, useTable } from '@/hooks'
|
||||
|
||||
defineOptions({ name: 'OperationLog' })
|
||||
|
||||
const queryForm = reactive<LogQuery>({
|
||||
createTime: [
|
||||
dayjs().subtract(6, 'day').startOf('day').format('YYYY-MM-DD HH:mm:ss'),
|
||||
dayjs().endOf('day').format('YYYY-MM-DD HH:mm:ss')
|
||||
],
|
||||
sort: ['createTime,desc']
|
||||
})
|
||||
|
||||
const {
|
||||
loading,
|
||||
tableData: dataList,
|
||||
pagination,
|
||||
search
|
||||
} = useTable((p) => listLog({ ...queryForm, page: p.page, size: p.size }), { immediate: true })
|
||||
|
||||
// 重置
|
||||
const reset = () => {
|
||||
queryForm.description = undefined
|
||||
queryForm.ip = undefined
|
||||
queryForm.createUserString = undefined
|
||||
queryForm.createTime = [
|
||||
dayjs().subtract(6, 'day').startOf('day').format('YYYY-MM-DD HH:mm:ss'),
|
||||
dayjs().endOf('day').format('YYYY-MM-DD HH:mm:ss')
|
||||
]
|
||||
queryForm.status = undefined
|
||||
search()
|
||||
}
|
||||
|
||||
const columns: TableInstanceColumns[] = [
|
||||
{
|
||||
title: '序号',
|
||||
@@ -102,21 +130,6 @@ const columns: TableInstanceColumns[] = [
|
||||
{ title: '终端系统', dataIndex: 'os', ellipsis: true, tooltip: true }
|
||||
]
|
||||
|
||||
const queryForm = reactive<LogQuery>({
|
||||
createTime: [
|
||||
dayjs().subtract(6, 'day').startOf('day').format('YYYY-MM-DD HH:mm:ss'),
|
||||
dayjs().endOf('day').format('YYYY-MM-DD HH:mm:ss')
|
||||
],
|
||||
sort: ['createTime,desc']
|
||||
})
|
||||
|
||||
const {
|
||||
loading,
|
||||
tableData: dataList,
|
||||
pagination,
|
||||
search
|
||||
} = useTable((p) => listLog({ ...queryForm, page: p.page, size: p.size }), { immediate: true })
|
||||
|
||||
// 过滤查询
|
||||
const filterChange = (dataIndex, filteredValues) => {
|
||||
try {
|
||||
@@ -128,19 +141,6 @@ const filterChange = (dataIndex, filteredValues) => {
|
||||
}
|
||||
}
|
||||
|
||||
// 重置
|
||||
const reset = () => {
|
||||
queryForm.description = undefined
|
||||
queryForm.ip = undefined
|
||||
queryForm.createUserString = undefined
|
||||
queryForm.createTime = [
|
||||
dayjs().subtract(6, 'day').startOf('day').format('YYYY-MM-DD HH:mm:ss'),
|
||||
dayjs().endOf('day').format('YYYY-MM-DD HH:mm:ss')
|
||||
]
|
||||
queryForm.status = undefined
|
||||
search()
|
||||
}
|
||||
|
||||
// 导出
|
||||
const onExport = () => {
|
||||
useDownload(() => exportOperationLog(queryForm))
|
||||
|
||||
@@ -8,7 +8,7 @@
|
||||
:loading="loading"
|
||||
:scroll="{ x: '100%', y: '100%', minWidth: 1000 }"
|
||||
:pagination="pagination"
|
||||
:disabledTools="['size', 'setting']"
|
||||
:disabled-tools="['size', 'setting']"
|
||||
@refresh="search"
|
||||
>
|
||||
<template #custom-left>
|
||||
@@ -44,8 +44,8 @@
|
||||
</template>
|
||||
|
||||
<script setup lang="ts">
|
||||
import { listOnlineUser, kickout, type OnlineUserQuery } from '@/apis'
|
||||
import { Message } from '@arco-design/web-vue'
|
||||
import { type OnlineUserQuery, kickout, listOnlineUser } from '@/apis'
|
||||
import type { TableInstanceColumns } from '@/components/GiTable/type'
|
||||
import DateRangePicker from '@/components/DateRangePicker/index.vue'
|
||||
import { useUserStore } from '@/stores'
|
||||
@@ -57,6 +57,25 @@ defineOptions({ name: 'MonitorOnline' })
|
||||
|
||||
const userStore = useUserStore()
|
||||
const currentToken = userStore.token
|
||||
|
||||
const queryForm = reactive<OnlineUserQuery>({
|
||||
sort: ['createTime,desc']
|
||||
})
|
||||
|
||||
const {
|
||||
tableData: dataList,
|
||||
loading,
|
||||
pagination,
|
||||
search
|
||||
} = useTable((p) => listOnlineUser({ ...queryForm, page: p.page, size: p.size }), { immediate: true })
|
||||
|
||||
// 重置
|
||||
const reset = () => {
|
||||
queryForm.nickname = undefined
|
||||
queryForm.loginTime = undefined
|
||||
search()
|
||||
}
|
||||
|
||||
const columns: TableInstanceColumns[] = [
|
||||
{
|
||||
title: '序号',
|
||||
@@ -79,24 +98,6 @@ const columns: TableInstanceColumns[] = [
|
||||
}
|
||||
]
|
||||
|
||||
const queryForm = reactive<OnlineUserQuery>({
|
||||
sort: ['createTime,desc']
|
||||
})
|
||||
|
||||
const {
|
||||
tableData: dataList,
|
||||
loading,
|
||||
pagination,
|
||||
search
|
||||
} = useTable((p) => listOnlineUser({ ...queryForm, page: p.page, size: p.size }), { immediate: true })
|
||||
|
||||
// 重置
|
||||
const reset = () => {
|
||||
queryForm.nickname = undefined
|
||||
queryForm.loginTime = undefined
|
||||
search()
|
||||
}
|
||||
|
||||
// 强退
|
||||
const handleKickout = (token: string) => {
|
||||
kickout(token).then(() => {
|
||||
|
||||
@@ -19,8 +19,8 @@
|
||||
|
||||
<script setup lang="ts">
|
||||
// import { getSmsCaptcha, getEmailCaptcha, updateUserEmail, updateUserPhone } from '@/apis'
|
||||
import { updateUserPassword } from '@/apis'
|
||||
import { Message } from '@arco-design/web-vue'
|
||||
import { updateUserPassword } from '@/apis'
|
||||
import { encryptByRsa } from '@/utils/encrypt'
|
||||
import { useUserStore } from '@/stores'
|
||||
import { type Columns, GiForm } from '@/components/GiForm'
|
||||
@@ -117,13 +117,6 @@ const { form, resetForm } = useForm({
|
||||
rePassword: ''
|
||||
})
|
||||
|
||||
// 重置
|
||||
const reset = () => {
|
||||
formRef.value?.formRef?.resetFields()
|
||||
resetForm()
|
||||
resetCaptcha()
|
||||
}
|
||||
|
||||
const captchaTimer = ref()
|
||||
const captchaTime = ref(60)
|
||||
const captchaBtnName = ref('获取验证码')
|
||||
@@ -136,6 +129,13 @@ const resetCaptcha = () => {
|
||||
captchaDisable.value = false
|
||||
}
|
||||
|
||||
// 重置
|
||||
const reset = () => {
|
||||
formRef.value?.formRef?.resetFields()
|
||||
resetForm()
|
||||
resetCaptcha()
|
||||
}
|
||||
|
||||
const captchaLoading = ref(false)
|
||||
// 获取验证码
|
||||
const onCaptcha = async () => {
|
||||
|
||||
@@ -95,10 +95,10 @@
|
||||
</template>
|
||||
|
||||
<script setup lang="ts">
|
||||
import { uploadAvatar } from '@/apis'
|
||||
import BasicInfoUpdateModal from './BasicInfoUpdateModal.vue'
|
||||
import { Message, type FileItem } from '@arco-design/web-vue'
|
||||
import { type FileItem, Message } from '@arco-design/web-vue'
|
||||
import { VueCropper } from 'vue-cropper'
|
||||
import BasicInfoUpdateModal from './BasicInfoUpdateModal.vue'
|
||||
import { uploadAvatar } from '@/apis'
|
||||
import 'vue-cropper/dist/index.css'
|
||||
import { useUserStore } from '@/stores'
|
||||
import getAvatar from '@/utils/avatar'
|
||||
|
||||
@@ -5,9 +5,9 @@
|
||||
</template>
|
||||
|
||||
<script setup lang="ts">
|
||||
import { updateUserBaseInfo } from '@/apis'
|
||||
import { Message } from '@arco-design/web-vue'
|
||||
import { GiForm, type Columns } from '@/components/GiForm'
|
||||
import { updateUserBaseInfo } from '@/apis'
|
||||
import { type Columns, GiForm } from '@/components/GiForm'
|
||||
import { useForm } from '@/hooks'
|
||||
import { useUserStore } from '@/stores'
|
||||
|
||||
|
||||
@@ -19,7 +19,7 @@
|
||||
</div>
|
||||
<div class="btn-wrapper">
|
||||
<a-button
|
||||
v-if="item.jumpMode == 'modal'"
|
||||
v-if="item.jumpMode === 'modal'"
|
||||
class="btn"
|
||||
:type="item.status ? 'secondary' : 'primary'"
|
||||
@click="onUpdate(item.type, item.status)"
|
||||
@@ -35,9 +35,9 @@
|
||||
</template>
|
||||
|
||||
<script lang="ts" setup>
|
||||
import { listOption, type OptionResp, type SecurityConfigResp } from '@/apis'
|
||||
import type { ModeItem } from '../type'
|
||||
import VerifyModel from '../components/VerifyModel.vue'
|
||||
import { type OptionResp, type SecurityConfigResp, listOption } from '@/apis'
|
||||
import { useUserStore } from '@/stores'
|
||||
|
||||
const userStore = useUserStore()
|
||||
@@ -48,7 +48,7 @@ modeList.value = [
|
||||
{
|
||||
title: '安全手机',
|
||||
icon: 'phone-color',
|
||||
value: `${userInfo.value.phone + ' ' || '手机号'}`,
|
||||
value: `${`${userInfo.value.phone} ` || '手机号'}`,
|
||||
subtitle: `可用于身份验证、密码找回、通知接收`,
|
||||
type: 'phone',
|
||||
jumpMode: 'modal',
|
||||
@@ -58,7 +58,7 @@ modeList.value = [
|
||||
{
|
||||
title: '安全邮箱',
|
||||
icon: 'email-color',
|
||||
value: `${userInfo.value.email + ' ' || '邮箱'}`,
|
||||
value: `${`${userInfo.value.email} ` || '邮箱'}`,
|
||||
subtitle: `可用于身份验证、密码找回、通知接收`,
|
||||
type: 'email',
|
||||
jumpMode: 'modal',
|
||||
@@ -96,7 +96,7 @@ const securityConfig = ref<SecurityConfigResp>({
|
||||
const getDataList = async () => {
|
||||
const { data } = await listOption({ code: Object.keys(securityConfig.value) })
|
||||
securityConfig.value = data.reduce((obj: SecurityConfigResp, option: OptionResp) => {
|
||||
obj[option.code] = { ...option, value: parseInt(option.value) }
|
||||
obj[option.code] = { ...option, value: Number.parseInt(option.value) }
|
||||
return obj
|
||||
}, {})
|
||||
}
|
||||
|
||||
@@ -21,7 +21,7 @@
|
||||
</div>
|
||||
<div class="btn-wrapper">
|
||||
<a-button
|
||||
v-if="item.jumpMode == 'modal'"
|
||||
v-if="item.jumpMode === 'modal'"
|
||||
class="btn"
|
||||
:type="item.status ? 'secondary' : 'primary'"
|
||||
@click="onUpdate(item.type, item.status)"
|
||||
@@ -29,7 +29,7 @@
|
||||
{{ item.status ? '修改' : '绑定' }}
|
||||
</a-button>
|
||||
<a-button
|
||||
v-else-if="item.jumpMode == 'link'"
|
||||
v-else-if="item.jumpMode === 'link'"
|
||||
class="btn"
|
||||
:type="item.status ? 'secondary' : 'primary'"
|
||||
@click="onBinding(item.type, item.status)"
|
||||
@@ -44,13 +44,12 @@
|
||||
</template>
|
||||
|
||||
<script setup lang="ts">
|
||||
import { socialAuth, listUserSocial, unbindSocialAccount } from '@/apis'
|
||||
import type { ModeItem } from '../type'
|
||||
import VerifyModel from '../components/VerifyModel.vue'
|
||||
import { listUserSocial, socialAuth, unbindSocialAccount } from '@/apis'
|
||||
import { useUserStore } from '@/stores'
|
||||
|
||||
const userStore = useUserStore()
|
||||
const userInfo = computed(() => userStore.userInfo)
|
||||
|
||||
const socialList = ref<any>([])
|
||||
const modeList = ref<ModeItem[]>([])
|
||||
@@ -58,18 +57,18 @@ modeList.value = [
|
||||
{
|
||||
title: '绑定 Gitee',
|
||||
icon: 'gitee',
|
||||
subtitle: `${socialList.value.some((el) => el == 'gitee') ? '' : '绑定后,'}可通过 Gitee 进行登录`,
|
||||
subtitle: `${socialList.value.includes('gitee') ? '' : '绑定后,'}可通过 Gitee 进行登录`,
|
||||
jumpMode: 'link',
|
||||
type: 'gitee',
|
||||
status: socialList.value.some((el) => el == 'gitee')
|
||||
status: socialList.value.includes('gitee')
|
||||
},
|
||||
{
|
||||
title: '绑定 GitHub',
|
||||
icon: 'github',
|
||||
subtitle: `${socialList.value.some((el) => el == 'gitee') ? '' : '绑定后,'}可通过 GitHub 进行登录`,
|
||||
subtitle: `${socialList.value.includes('gitee') ? '' : '绑定后,'}可通过 GitHub 进行登录`,
|
||||
type: 'github',
|
||||
jumpMode: 'link',
|
||||
status: socialList.value.some((el) => el == 'github')
|
||||
status: socialList.value.includes('github')
|
||||
}
|
||||
]
|
||||
|
||||
@@ -81,7 +80,7 @@ const onBinding = (type: string, status: boolean) => {
|
||||
})
|
||||
} else {
|
||||
unbindSocialAccount(type).then((res) => {
|
||||
if (res.code == 200) {
|
||||
if (res.code === 200) {
|
||||
userStore.getInfo()
|
||||
}
|
||||
})
|
||||
|
||||
@@ -85,7 +85,7 @@
|
||||
v-model.trim="form.site_copyright"
|
||||
placeholder="请输入版权信息"
|
||||
:auto-size="{
|
||||
minRows: 3
|
||||
minRows: 3,
|
||||
}"
|
||||
show-word-limit
|
||||
/>
|
||||
@@ -130,8 +130,8 @@
|
||||
</template>
|
||||
|
||||
<script lang="ts" setup>
|
||||
import { listOption, updateOption, resetOptionValue, uploadFile, type OptionResp } from '@/apis'
|
||||
import { Message, Modal, type FileItem, type FormInstance, type RequestOption } from '@arco-design/web-vue'
|
||||
import { type FileItem, type FormInstance, Message, Modal, type RequestOption } from '@arco-design/web-vue'
|
||||
import { type OptionResp, listOption, resetOptionValue, updateOption, uploadFile } from '@/apis'
|
||||
import { useAppStore } from '@/stores'
|
||||
import { useForm } from '@/hooks'
|
||||
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
<template>
|
||||
<a-form style="margin-top: 20px" ref="formRef" :model="form" size="small" label-align="left" :disabled="!isUpdate">
|
||||
<a-form ref="formRef" style="margin-top: 20px" :model="form" size="small" label-align="left" :disabled="!isUpdate">
|
||||
<a-list size="small" :bordered="false">
|
||||
<a-list-item style="border: none">
|
||||
<a-form-item
|
||||
@@ -7,43 +7,43 @@
|
||||
:label="form.password_expiration_days.name"
|
||||
field="password_expiration_days"
|
||||
>
|
||||
<a-input-number class="input-width" :min="0" :max="999" v-model="form.password_expiration_days.value">
|
||||
<a-input-number v-model="form.password_expiration_days.value" class="input-width" :min="0" :max="999">
|
||||
<template #append>天</template>
|
||||
</a-input-number>
|
||||
</a-form-item>
|
||||
</a-list-item>
|
||||
<a-list-item style="border: none">
|
||||
<a-form-item :help="form.password_min_length.description" :label="form.password_min_length.name">
|
||||
<a-input-number class="input-width" :min="8" :max="32" v-model="form.password_min_length.value" />
|
||||
<a-input-number v-model="form.password_min_length.value" class="input-width" :min="8" :max="32" />
|
||||
</a-form-item>
|
||||
</a-list-item>
|
||||
<a-list-item style="border: none">
|
||||
<a-form-item :help="form.password_update_interval.description" :label="form.password_update_interval.name">
|
||||
<a-input-number class="input-width" :min="0" :max="9999" v-model="form.password_update_interval.value">
|
||||
<a-input-number v-model="form.password_update_interval.value" class="input-width" :min="0" :max="9999">
|
||||
<template #append>分钟</template>
|
||||
</a-input-number>
|
||||
</a-form-item>
|
||||
</a-list-item>
|
||||
<a-list-item style="border: none">
|
||||
<a-form-item :help="form.password_error_count.description" :label="form.password_error_count.name">
|
||||
<a-input-number class="input-width" :min="0" :max="9999" v-model="form.password_error_count.value" />
|
||||
<a-input-number v-model="form.password_error_count.value" class="input-width" :min="0" :max="9999" />
|
||||
</a-form-item>
|
||||
</a-list-item>
|
||||
<a-list-item style="border: none">
|
||||
<a-form-item :help="form.password_lock_minutes.description" :label="form.password_lock_minutes.name">
|
||||
<a-input-number class="input-width" :min="0" :max="9999" v-model="form.password_lock_minutes.value">
|
||||
<a-input-number v-model="form.password_lock_minutes.value" class="input-width" :min="0" :max="9999">
|
||||
<template #append>分钟</template>
|
||||
</a-input-number>
|
||||
</a-form-item>
|
||||
</a-list-item>
|
||||
<a-list-item style="border: none">
|
||||
<a-form-item :help="form.password_special_char.description" :label="form.password_special_char.name">
|
||||
<a-switch type="round" :checked-value="1" :unchecked-value="0" v-model="form.password_special_char.value" />
|
||||
<a-switch v-model="form.password_special_char.value" type="round" :checked-value="1" :unchecked-value="0" />
|
||||
</a-form-item>
|
||||
</a-list-item>
|
||||
<a-list-item style="border: none">
|
||||
<a-form-item :help="form.password_contain_name.description" :label="form.password_contain_name.name">
|
||||
<a-switch type="round" :checked-value="1" :unchecked-value="0" v-model="form.password_contain_name.value" />
|
||||
<a-switch v-model="form.password_contain_name.value" type="round" :checked-value="1" :unchecked-value="0" />
|
||||
</a-form-item>
|
||||
</a-list-item>
|
||||
<a-list-item style="padding-top: 13px; border: none">
|
||||
@@ -85,8 +85,8 @@
|
||||
</template>
|
||||
|
||||
<script setup lang="ts">
|
||||
import { listOption, updateOption, resetOptionValue, type SecurityConfigResp, type OptionResp } from '@/apis'
|
||||
import { Message, Modal, type FormInstance } from '@arco-design/web-vue'
|
||||
import { type FormInstance, Message, Modal } from '@arco-design/web-vue'
|
||||
import { type OptionResp, type SecurityConfigResp, listOption, resetOptionValue, updateOption } from '@/apis'
|
||||
|
||||
const formRef = ref<FormInstance>()
|
||||
|
||||
@@ -100,23 +100,12 @@ const form = ref<SecurityConfigResp>({
|
||||
password_update_interval: {}
|
||||
})
|
||||
|
||||
// 重置
|
||||
const reset = () => {
|
||||
getDataList()
|
||||
}
|
||||
|
||||
const isUpdate = ref(false)
|
||||
// 修改
|
||||
const onUpdate = () => {
|
||||
isUpdate.value = true
|
||||
}
|
||||
|
||||
// 取消
|
||||
const handleCancel = () => {
|
||||
reset()
|
||||
isUpdate.value = false
|
||||
}
|
||||
|
||||
const queryForm = {
|
||||
code: Object.keys(form.value)
|
||||
}
|
||||
@@ -124,11 +113,22 @@ const queryForm = {
|
||||
const getDataList = async () => {
|
||||
const { data } = await listOption(queryForm)
|
||||
form.value = data.reduce((obj: SecurityConfigResp, option: OptionResp) => {
|
||||
obj[option.code] = { ...option, value: parseInt(option.value) }
|
||||
obj[option.code] = { ...option, value: Number.parseInt(option.value) }
|
||||
return obj
|
||||
}, {})
|
||||
}
|
||||
|
||||
// 重置
|
||||
const reset = () => {
|
||||
getDataList()
|
||||
}
|
||||
|
||||
// 取消
|
||||
const handleCancel = () => {
|
||||
reset()
|
||||
isUpdate.value = false
|
||||
}
|
||||
|
||||
// 保存
|
||||
const handleSave = async () => {
|
||||
await updateOption(
|
||||
|
||||
@@ -14,13 +14,17 @@
|
||||
</template>
|
||||
|
||||
<script setup lang="ts">
|
||||
import { getDept, addDept, updateDept } from '@/apis'
|
||||
import type { DeptReq } from './type'
|
||||
import { Message } from '@arco-design/web-vue'
|
||||
import { GiForm, type Columns } from '@/components/GiForm'
|
||||
import type { DeptReq } from './type'
|
||||
import { addDept, getDept, updateDept } from '@/apis'
|
||||
import { type Columns, GiForm } from '@/components/GiForm'
|
||||
import { useForm } from '@/hooks'
|
||||
import { useDept } from '@/hooks/app'
|
||||
|
||||
const emit = defineEmits<{
|
||||
(e: 'save-success'): void
|
||||
}>()
|
||||
|
||||
const { deptList, getDeptList } = useDept()
|
||||
|
||||
const dataId = ref('')
|
||||
@@ -49,7 +53,7 @@ const columns: Columns = [
|
||||
fallbackOption: false,
|
||||
filterTreeNode(searchKey, nodeData) {
|
||||
if (nodeData.title) {
|
||||
return nodeData.title.toLowerCase().indexOf(searchKey.toLowerCase()) > -1
|
||||
return nodeData.title.toLowerCase().includes(searchKey.toLowerCase())
|
||||
}
|
||||
return false
|
||||
}
|
||||
@@ -147,9 +151,5 @@ const save = async () => {
|
||||
}
|
||||
}
|
||||
|
||||
const emit = defineEmits<{
|
||||
(e: 'save-success'): void
|
||||
}>()
|
||||
|
||||
defineExpose({ onAdd, onUpdate })
|
||||
</script>
|
||||
|
||||
@@ -9,8 +9,8 @@
|
||||
:loading="loading"
|
||||
:scroll="{ x: '100%', y: '100%', minWidth: 1000 }"
|
||||
:pagination="false"
|
||||
:disabledTools="['size']"
|
||||
:disabledColumnKeys="['name']"
|
||||
:disabled-tools="['size']"
|
||||
:disabled-column-keys="['name']"
|
||||
@refresh="search"
|
||||
>
|
||||
<template #expand-icon="{ expanded }">
|
||||
@@ -80,9 +80,9 @@
|
||||
</template>
|
||||
|
||||
<script setup lang="ts">
|
||||
import { listDept, deleteDept, exportDept, type DeptResp, type DeptQuery } from '@/apis'
|
||||
import DeptAddModal from './DeptAddModal.vue'
|
||||
import { Message } from '@arco-design/web-vue'
|
||||
import DeptAddModal from './DeptAddModal.vue'
|
||||
import { type DeptQuery, type DeptResp, deleteDept, exportDept, listDept } from '@/apis'
|
||||
import type GiTable from '@/components/GiTable/index.vue'
|
||||
import type { TableInstanceColumns } from '@/components/GiTable/type'
|
||||
import { useDownload } from '@/hooks'
|
||||
|
||||
@@ -14,11 +14,14 @@
|
||||
</template>
|
||||
|
||||
<script setup lang="ts">
|
||||
import { getDict, addDict, updateDict } from '@/apis'
|
||||
import { Message } from '@arco-design/web-vue'
|
||||
import { GiForm, type Columns } from '@/components/GiForm'
|
||||
import { addDict, getDict, updateDict } from '@/apis'
|
||||
import { type Columns, GiForm } from '@/components/GiForm'
|
||||
import { useForm } from '@/hooks'
|
||||
|
||||
const emit = defineEmits<{
|
||||
(e: 'save-success'): void
|
||||
}>()
|
||||
const dataId = ref('')
|
||||
const isUpdate = computed(() => !!dataId.value)
|
||||
const title = computed(() => (isUpdate.value ? '修改字典' : '新增字典'))
|
||||
@@ -91,9 +94,5 @@ const save = async () => {
|
||||
}
|
||||
}
|
||||
|
||||
const emit = defineEmits<{
|
||||
(e: 'save-success'): void
|
||||
}>()
|
||||
|
||||
defineExpose({ onAdd, onUpdate })
|
||||
</script>
|
||||
|
||||
@@ -8,8 +8,8 @@
|
||||
:loading="loading"
|
||||
:scroll="{ x: '100%', y: '100%', minWidth: 1000 }"
|
||||
:pagination="pagination"
|
||||
:disabledTools="['size']"
|
||||
:disabledColumnKeys="['name']"
|
||||
:disabled-tools="['size']"
|
||||
:disabled-column-keys="['name']"
|
||||
@refresh="search"
|
||||
>
|
||||
<template #custom-left>
|
||||
@@ -52,8 +52,8 @@
|
||||
</template>
|
||||
|
||||
<script setup lang="ts">
|
||||
import { listDict, deleteDict, type DictResp, type DictQuery } from '@/apis'
|
||||
import DictAddModal from './DictAddModal.vue'
|
||||
import { type DictQuery, type DictResp, deleteDict, listDict } from '@/apis'
|
||||
import DictItemModal from '@/views/system/dict/item/index.vue'
|
||||
import type { TableInstanceColumns } from '@/components/GiTable/type'
|
||||
import { useTable } from '@/hooks'
|
||||
@@ -62,6 +62,24 @@ import has from '@/utils/has'
|
||||
|
||||
defineOptions({ name: 'SystemDict' })
|
||||
|
||||
const queryForm = reactive<DictQuery>({
|
||||
sort: ['createTime,desc']
|
||||
})
|
||||
|
||||
const {
|
||||
tableData: dataList,
|
||||
loading,
|
||||
pagination,
|
||||
search,
|
||||
handleDelete
|
||||
} = useTable((p) => listDict({ ...queryForm, page: p.page, size: p.size }), { immediate: true })
|
||||
|
||||
// 重置
|
||||
const reset = () => {
|
||||
queryForm.description = undefined
|
||||
search()
|
||||
}
|
||||
|
||||
const columns: TableInstanceColumns[] = [
|
||||
{
|
||||
title: '序号',
|
||||
@@ -87,24 +105,6 @@ const columns: TableInstanceColumns[] = [
|
||||
}
|
||||
]
|
||||
|
||||
const queryForm = reactive<DictQuery>({
|
||||
sort: ['createTime,desc']
|
||||
})
|
||||
|
||||
const {
|
||||
tableData: dataList,
|
||||
loading,
|
||||
pagination,
|
||||
search,
|
||||
handleDelete
|
||||
} = useTable((p) => listDict({ ...queryForm, page: p.page, size: p.size }), { immediate: true })
|
||||
|
||||
// 重置
|
||||
const reset = () => {
|
||||
queryForm.description = undefined
|
||||
search()
|
||||
}
|
||||
|
||||
// 删除
|
||||
const onDelete = (item: DictResp) => {
|
||||
return handleDelete(() => deleteDict(item.id), { content: `是否确定删除字典 [${item.name}]?`, showModal: true })
|
||||
|
||||
@@ -22,11 +22,14 @@
|
||||
</template>
|
||||
|
||||
<script setup lang="ts">
|
||||
import { getDictItem, addDictItem, updateDictItem } from '@/apis'
|
||||
import { Message } from '@arco-design/web-vue'
|
||||
import { GiForm, type Columns } from '@/components/GiForm'
|
||||
import { addDictItem, getDictItem, updateDictItem } from '@/apis'
|
||||
import { type Columns, GiForm } from '@/components/GiForm'
|
||||
import { useForm } from '@/hooks'
|
||||
|
||||
const emit = defineEmits<{
|
||||
(e: 'save-success'): void
|
||||
}>()
|
||||
const dictId = ref('')
|
||||
const dataId = ref('')
|
||||
const isUpdate = computed(() => !!dataId.value)
|
||||
@@ -126,9 +129,5 @@ const save = async () => {
|
||||
}
|
||||
}
|
||||
|
||||
const emit = defineEmits<{
|
||||
(e: 'save-success'): void
|
||||
}>()
|
||||
|
||||
defineExpose({ onAdd, onUpdate })
|
||||
</script>
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
<template>
|
||||
<a-modal
|
||||
v-model:visible="visible"
|
||||
:title="'字典项管理(' + dictCode + ')'"
|
||||
:title="`字典项管理(${dictCode})`"
|
||||
title-align="start"
|
||||
:mask-closable="false"
|
||||
:esc-to-close="false"
|
||||
@@ -11,15 +11,14 @@
|
||||
hide-cancel
|
||||
>
|
||||
<GiTable
|
||||
ref="tableRef"
|
||||
row-key="id"
|
||||
:data="dataList"
|
||||
:columns="columns"
|
||||
:loading="loading"
|
||||
:scroll="{ x: '100%', y: '100%', minWidth: 800 }"
|
||||
:pagination="pagination"
|
||||
:disabledTools="['size']"
|
||||
:disabledColumnKeys="['label']"
|
||||
:disabled-tools="['size']"
|
||||
:disabled-column-keys="['label']"
|
||||
@refresh="search"
|
||||
>
|
||||
<template #custom-left>
|
||||
@@ -63,14 +62,38 @@
|
||||
</template>
|
||||
|
||||
<script lang="ts" setup>
|
||||
import { listDictItem, deleteDictItem, type DictItemResp, type DictItemQuery } from '@/apis'
|
||||
import { useWindowSize } from '@vueuse/core'
|
||||
import DictItemAddModal from './DictItemAddModal.vue'
|
||||
import { type DictItemQuery, type DictItemResp, deleteDictItem, listDictItem } from '@/apis'
|
||||
import type { TableInstanceColumns } from '@/components/GiTable/type'
|
||||
import { useTable } from '@/hooks'
|
||||
import { isMobile } from '@/utils'
|
||||
import { useWindowSize } from '@vueuse/core'
|
||||
|
||||
const { width } = useWindowSize()
|
||||
|
||||
const dictId = ref('')
|
||||
|
||||
const queryForm = reactive<DictItemQuery>({
|
||||
sort: ['createTime,desc']
|
||||
})
|
||||
|
||||
const {
|
||||
tableData: dataList,
|
||||
loading,
|
||||
pagination,
|
||||
search,
|
||||
handleDelete
|
||||
} = useTable((p) => listDictItem({ ...queryForm, dictId: dictId.value, page: p.page, size: p.size }), {
|
||||
immediate: true
|
||||
})
|
||||
|
||||
// 重置
|
||||
const reset = () => {
|
||||
queryForm.description = undefined
|
||||
queryForm.status = undefined
|
||||
search()
|
||||
}
|
||||
|
||||
const columns: TableInstanceColumns[] = [
|
||||
{
|
||||
title: '序号',
|
||||
@@ -99,11 +122,6 @@ const columns: TableInstanceColumns[] = [
|
||||
{ title: '操作', slotName: 'action', width: 130, align: 'center', fixed: !isMobile() ? 'right' : undefined }
|
||||
]
|
||||
|
||||
const queryForm = reactive<DictItemQuery>({
|
||||
sort: ['createTime,desc']
|
||||
})
|
||||
|
||||
const dictId = ref('')
|
||||
const dictCode = ref('')
|
||||
const visible = ref(false)
|
||||
// 打开
|
||||
@@ -116,23 +134,6 @@ const open = (id: string, code: string) => {
|
||||
}
|
||||
defineExpose({ open })
|
||||
|
||||
const {
|
||||
tableData: dataList,
|
||||
loading,
|
||||
pagination,
|
||||
search,
|
||||
handleDelete
|
||||
} = useTable((p) => listDictItem({ ...queryForm, dictId: dictId.value, page: p.page, size: p.size }), {
|
||||
immediate: true
|
||||
})
|
||||
|
||||
// 重置
|
||||
const reset = () => {
|
||||
queryForm.description = undefined
|
||||
queryForm.status = undefined
|
||||
search()
|
||||
}
|
||||
|
||||
// 删除
|
||||
const onDelete = (item: DictItemResp) => {
|
||||
return handleDelete(() => deleteDictItem(item.id), { content: `是否确定删除 [${item.label}]?`, showModal: false })
|
||||
|
||||
@@ -20,7 +20,7 @@
|
||||
</template>
|
||||
|
||||
<script setup lang="ts">
|
||||
import { useDraggable, useWindowSize, useElementSize } from '@vueuse/core'
|
||||
import { useDraggable, useElementSize, useWindowSize } from '@vueuse/core'
|
||||
import type { FileItem } from '@/apis'
|
||||
|
||||
interface Props {
|
||||
@@ -71,8 +71,8 @@ const audioStyle = computed(() => {
|
||||
}
|
||||
sessionStorage.setItem('AudioDialogXY', JSON.stringify({ top, left }))
|
||||
return {
|
||||
left: left + 'px',
|
||||
top: top + 'px'
|
||||
left: `${left}px`,
|
||||
top: `${top}px`
|
||||
}
|
||||
})
|
||||
|
||||
|
||||
@@ -2,9 +2,8 @@ import type { Component } from 'vue'
|
||||
import { createApp } from 'vue'
|
||||
import ArcoVueIcon from '@arco-design/web-vue/es/icon'
|
||||
import ArcoVue from '@arco-design/web-vue'
|
||||
import type { FileItem } from '@/apis'
|
||||
|
||||
import ModalContent from './ModalContent.vue'
|
||||
import type { FileItem } from '@/apis'
|
||||
|
||||
function createModal<T extends { callback?: () => void }>(component: Component, options?: T) {
|
||||
// 创建一个挂载容器
|
||||
@@ -28,7 +27,7 @@ function createModal<T extends { callback?: () => void }>(component: Component,
|
||||
instance.use(ArcoVueIcon)
|
||||
instance.mount(el)
|
||||
}
|
||||
type TFileOptions = { data: FileItem; callback?: () => void }
|
||||
type TFileOptions = { data: FileItem, callback?: () => void }
|
||||
|
||||
/** 预览 音频文件 弹窗 */
|
||||
let fileAudioId = ''
|
||||
@@ -36,7 +35,7 @@ export function previewFileAudioModal(data: FileItem) {
|
||||
if (fileAudioId) return // 防止重复打开
|
||||
fileAudioId = data.id
|
||||
return createModal<TFileOptions>(ModalContent, {
|
||||
data: data,
|
||||
data,
|
||||
// 关闭的回调
|
||||
callback: () => {
|
||||
fileAudioId = ''
|
||||
|
||||
@@ -14,8 +14,8 @@
|
||||
</template>
|
||||
|
||||
<script setup lang="ts">
|
||||
import type { FileItem } from '@/apis'
|
||||
import FileImage from '../../main/FileMain/FileImage.vue'
|
||||
import type { FileItem } from '@/apis'
|
||||
import { formatFileSize } from '@/utils'
|
||||
|
||||
interface Props {
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
import type { FileItem } from '@/apis'
|
||||
import { h } from 'vue'
|
||||
import { Modal } from '@arco-design/web-vue'
|
||||
import ModalContent from './ModalContent.vue'
|
||||
import type { FileItem } from '@/apis'
|
||||
|
||||
/** 打开 详情 弹窗 */
|
||||
export function openFileDetailModal(fileItem: FileItem) {
|
||||
|
||||
@@ -14,8 +14,8 @@
|
||||
</template>
|
||||
|
||||
<script lang="ts" setup>
|
||||
import type { FileItem } from '@/apis'
|
||||
import type { FormInstance } from '@arco-design/web-vue'
|
||||
import type { FileItem } from '@/apis'
|
||||
|
||||
interface Props {
|
||||
data: FileItem
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
import { updateFile, type FileItem } from '@/apis'
|
||||
import { ref, h } from 'vue'
|
||||
import { Modal, Message } from '@arco-design/web-vue'
|
||||
import { h, ref } from 'vue'
|
||||
import { Message, Modal } from '@arco-design/web-vue'
|
||||
import ModalContent from './ModalContent.vue'
|
||||
import { type FileItem, updateFile } from '@/apis'
|
||||
|
||||
export function openFileRenameModal(data: FileItem, callback?: () => void) {
|
||||
const ModalContentRef = ref<InstanceType<typeof ModalContent>>()
|
||||
|
||||
@@ -8,6 +8,6 @@ export function previewFileVideoModal(data: FileItem) {
|
||||
title: '视频播放',
|
||||
width: 'auto',
|
||||
modalStyle: {},
|
||||
content: () => h(ModalContent, { data: data })
|
||||
content: () => h(ModalContent, { data })
|
||||
})
|
||||
}
|
||||
|
||||
@@ -15,21 +15,21 @@
|
||||
</template>
|
||||
|
||||
<script setup lang="ts">
|
||||
import { getFileStatistics, type FileStatisticsResp } from '@/apis'
|
||||
import { useChart } from '@/hooks'
|
||||
import { FileTypeList } from '@/constant/file'
|
||||
import VCharts from 'vue-echarts'
|
||||
import { use } from 'echarts/core'
|
||||
import { PieChart } from 'echarts/charts'
|
||||
import { TitleComponent, TooltipComponent, LegendComponent } from 'echarts/components'
|
||||
import { LegendComponent, TitleComponent, TooltipComponent } from 'echarts/components'
|
||||
import { CanvasRenderer } from 'echarts/renderers'
|
||||
import { FileTypeList } from '@/constant/file'
|
||||
import { useChart } from '@/hooks'
|
||||
import { type FileStatisticsResp, getFileStatistics } from '@/apis'
|
||||
import { formatFileSize } from '@/utils'
|
||||
|
||||
use([TitleComponent, TooltipComponent, LegendComponent, PieChart, CanvasRenderer])
|
||||
|
||||
const totalData = ref<FileStatisticsResp>({})
|
||||
const chartData = ref<Array<FileStatisticsResp>>([])
|
||||
const statisticValueStyle = { color: '#5856D6', 'font-size': '18px' }
|
||||
const statisticValueStyle = { 'color': '#5856D6', 'font-size': '18px' }
|
||||
const { option } = useChart(() => {
|
||||
return {
|
||||
grid: {
|
||||
@@ -50,7 +50,7 @@ const { option } = useChart(() => {
|
||||
},
|
||||
tooltip: {
|
||||
show: true,
|
||||
formatter: function (params) {
|
||||
formatter(params) {
|
||||
return `总计:${params.value}<br>${params.data.size}`
|
||||
}
|
||||
},
|
||||
@@ -78,12 +78,12 @@ const getStatisticsData = async () => {
|
||||
const { data: resData } = await getFileStatistics()
|
||||
const formatSize = formatFileSize(resData.size).split(' ')
|
||||
totalData.value = {
|
||||
size: parseFloat(formatSize[0]),
|
||||
size: Number.parseFloat(formatSize[0]),
|
||||
number: resData.number,
|
||||
unit: formatSize[1]
|
||||
}
|
||||
resData.data.forEach((fs: FileStatisticsResp) => {
|
||||
const matchedItem = FileTypeList.find((item) => item.value == fs.type)
|
||||
const matchedItem = FileTypeList.find((item) => item.value === fs.type)
|
||||
chartData.value.unshift({
|
||||
name: matchedItem ? matchedItem.name : '',
|
||||
value: fs.number,
|
||||
|
||||
@@ -46,7 +46,7 @@
|
||||
<a-table-column title="修改时间" data-index="updateTime" :width="200"></a-table-column>
|
||||
<a-table-column title="操作" :width="120" align="center">
|
||||
<template #cell="{ record }">
|
||||
<a-popover trigger="click" position="bottom" :content-style="{ padding: 0, 'margin-top': 0 }">
|
||||
<a-popover trigger="click" position="bottom" :content-style="{ 'padding': 0, 'margin-top': 0 }">
|
||||
<a-button type="text" @click.stop><icon-more :size="16" /></a-button>
|
||||
<template #content>
|
||||
<FileRightMenu
|
||||
@@ -64,10 +64,10 @@
|
||||
</template>
|
||||
|
||||
<script setup lang="ts">
|
||||
import type { FileItem } from '@/apis'
|
||||
import type { TableRowSelection, TableInstance } from '@arco-design/web-vue'
|
||||
import type { TableInstance, TableRowSelection } from '@arco-design/web-vue'
|
||||
import FileImage from './FileImage.vue'
|
||||
import FileRightMenu from './FileRightMenu.vue'
|
||||
import type { FileItem } from '@/apis'
|
||||
import { formatFileSize } from '@/utils'
|
||||
|
||||
interface Props {
|
||||
@@ -82,17 +82,17 @@ const props = withDefaults(defineProps<Props>(), {
|
||||
isBatchMode: false // 是否是批量模式
|
||||
})
|
||||
|
||||
const rowSelection: TableRowSelection = reactive({
|
||||
type: 'checkbox',
|
||||
showCheckedAll: true
|
||||
})
|
||||
|
||||
const emit = defineEmits<{
|
||||
(e: 'click', record: FileItem): void
|
||||
(e: 'select', record: FileItem): void
|
||||
(e: 'right-menu-click', mode: string, item: FileItem): void
|
||||
}>()
|
||||
|
||||
const rowSelection: TableRowSelection = reactive({
|
||||
type: 'checkbox',
|
||||
showCheckedAll: true
|
||||
})
|
||||
|
||||
// 多选
|
||||
const select: TableInstance['onSelect'] = (rowKeys, rowKey, record) => {
|
||||
emit('select', record as unknown as FileItem)
|
||||
|
||||
@@ -68,7 +68,7 @@
|
||||
<!-- 文件列表-宫格模式 -->
|
||||
<a-spin id="fileMain" class="file-main__list" :loading="loading" @scroll="handleScroll">
|
||||
<FileGrid
|
||||
v-show="fileList.length && mode == 'grid'"
|
||||
v-show="fileList.length && mode === 'grid'"
|
||||
:data="fileList"
|
||||
:is-batch-mode="isBatchMode"
|
||||
:selected-file-ids="selectedFileIds"
|
||||
@@ -79,7 +79,7 @@
|
||||
|
||||
<!-- 文件列表-列表模式 -->
|
||||
<FileList
|
||||
v-show="fileList.length && mode == 'list'"
|
||||
v-show="fileList.length && mode === 'list'"
|
||||
:data="fileList"
|
||||
:is-batch-mode="isBatchMode"
|
||||
:selected-file-ids="selectedFileIds"
|
||||
@@ -94,48 +94,22 @@
|
||||
</template>
|
||||
|
||||
<script setup lang="ts">
|
||||
import { listFile, uploadFile, deleteFile, type FileItem, type FileQuery, type FilePageQuery } from '@/apis'
|
||||
import { Message, Modal, type RequestOption } from '@arco-design/web-vue'
|
||||
import FileGrid from './FileGrid.vue'
|
||||
import { api as viewerApi } from 'v-viewer'
|
||||
import {
|
||||
openFileDetailModal,
|
||||
openFileRenameModal,
|
||||
previewFileVideoModal,
|
||||
previewFileAudioModal
|
||||
previewFileAudioModal,
|
||||
previewFileVideoModal
|
||||
} from '../../components/index'
|
||||
import FileGrid from './FileGrid.vue'
|
||||
import useFileManage from './useFileManage'
|
||||
import { type FileItem, type FilePageQuery, type FileQuery, deleteFile, listFile, uploadFile } from '@/apis'
|
||||
import { ImageTypes } from '@/constant/file'
|
||||
import { api as viewerApi } from 'v-viewer'
|
||||
import 'viewerjs/dist/viewer.css'
|
||||
import { downloadByUrl } from '@/utils/downloadFile'
|
||||
|
||||
const FileList = defineAsyncComponent(() => import('./FileList.vue'))
|
||||
onMounted(() => {
|
||||
const fileMainDom = document.getElementById('fileMain')
|
||||
fileMainDom.addEventListener('scrool', handleScroll)
|
||||
console.table('fileMainDom', fileMainDom)
|
||||
})
|
||||
onUnmounted(() => {
|
||||
// 移除事件监听
|
||||
const fileMainDom = document.getElementById('fileMain')
|
||||
fileMainDom.removeEventListener('scroll', handleScroll)
|
||||
})
|
||||
const timer = ref<any>()
|
||||
const handleScroll = (event) => {
|
||||
const { clientHeight, scrollHeight, scrollTop } = event.target
|
||||
const scrollLinerHeight = (clientHeight / scrollHeight) * scrollHeight
|
||||
if (!timer.value) {
|
||||
timer.value = setTimeout(() => {
|
||||
if ((scrollTop + scrollLinerHeight) / scrollHeight >= 0.9 && !loading.value) {
|
||||
++pagination.page
|
||||
getFileList()
|
||||
}
|
||||
timer.value = null
|
||||
}, 1000)
|
||||
}
|
||||
|
||||
console.log('event', event)
|
||||
}
|
||||
const route = useRoute()
|
||||
const { mode, selectedFileIds, toggleMode, addSelectedFileItem } = useFileManage()
|
||||
|
||||
@@ -148,9 +122,11 @@ const pagination = reactive({
|
||||
page: 1,
|
||||
size: 30
|
||||
})
|
||||
|
||||
const fileList = ref<FileItem[]>([])
|
||||
const isBatchMode = ref(false)
|
||||
const loading = ref(false)
|
||||
const timer = ref<any>()
|
||||
// 查询文件列表
|
||||
const getFileList = async (query: FilePageQuery = { ...queryForm, page: pagination.page, size: pagination.size }) => {
|
||||
try {
|
||||
@@ -179,6 +155,12 @@ const getFileList = async (query: FilePageQuery = { ...queryForm, page: paginati
|
||||
}
|
||||
}
|
||||
|
||||
// 查询
|
||||
const search = () => {
|
||||
pagination.page = 1
|
||||
getFileList()
|
||||
}
|
||||
|
||||
// 点击文件
|
||||
const handleClickFile = (item: FileItem) => {
|
||||
if (ImageTypes.includes(item.extension)) {
|
||||
@@ -222,7 +204,6 @@ const handleRightMenuClick = async (mode: string, fileInfo: FileItem) => {
|
||||
} else if (mode === 'detail') {
|
||||
openFileDetailModal(fileInfo)
|
||||
} else if (mode === 'download') {
|
||||
console.log('fileInfo', fileInfo)
|
||||
const res = await downloadByUrl({
|
||||
url: fileInfo.url,
|
||||
target: '_self',
|
||||
@@ -276,12 +257,30 @@ const handleUpload = (options: RequestOption) => {
|
||||
}
|
||||
}
|
||||
|
||||
// 查询
|
||||
const search = () => {
|
||||
pagination.page = 1
|
||||
getFileList()
|
||||
const handleScroll = (event) => {
|
||||
const { clientHeight, scrollHeight, scrollTop } = event.target
|
||||
const scrollLinerHeight = (clientHeight / scrollHeight) * scrollHeight
|
||||
if (!timer.value) {
|
||||
timer.value = setTimeout(() => {
|
||||
if ((scrollTop + scrollLinerHeight) / scrollHeight >= 0.9 && !loading.value) {
|
||||
++pagination.page
|
||||
getFileList()
|
||||
}
|
||||
timer.value = null
|
||||
}, 1000)
|
||||
}
|
||||
}
|
||||
|
||||
onMounted(() => {
|
||||
const fileMainDom = document.getElementById('fileMain')
|
||||
fileMainDom.addEventListener('scrool', handleScroll)
|
||||
})
|
||||
onUnmounted(() => {
|
||||
// 移除事件监听
|
||||
const fileMainDom = document.getElementById('fileMain')
|
||||
fileMainDom.removeEventListener('scroll', handleScroll)
|
||||
})
|
||||
|
||||
onBeforeRouteUpdate((to) => {
|
||||
if (!to.query.type) return
|
||||
queryForm.type = to.query.type?.toString()
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
import { ref, computed } from 'vue'
|
||||
import { computed, ref } from 'vue'
|
||||
import type { FileItem } from '@/apis'
|
||||
|
||||
type Mode = 'grid' | 'list'
|
||||
|
||||
@@ -26,10 +26,10 @@
|
||||
allow-search
|
||||
:data="(menuSelectTree as any)"
|
||||
:fallback-option="false"
|
||||
:fieldNames="{
|
||||
:field-names="{
|
||||
key: 'id',
|
||||
title: 'title',
|
||||
children: 'children'
|
||||
children: 'children',
|
||||
}"
|
||||
/>
|
||||
</a-form-item>
|
||||
@@ -120,12 +120,12 @@
|
||||
</template>
|
||||
|
||||
<script setup lang="ts">
|
||||
import { getMenu, addMenu, updateMenu, type MenuResp } from '@/apis'
|
||||
import { type FormInstance, Message } from '@arco-design/web-vue'
|
||||
import { mapTree } from 'xe-utils'
|
||||
import type { MenuForm } from './type'
|
||||
import { Message, type FormInstance } from '@arco-design/web-vue'
|
||||
import { type MenuResp, addMenu, getMenu, updateMenu } from '@/apis'
|
||||
import { useForm } from '@/hooks'
|
||||
import { filterTree, transformPathToName } from '@/utils'
|
||||
import { mapTree } from 'xe-utils'
|
||||
|
||||
interface Props {
|
||||
menus: MenuResp[]
|
||||
@@ -134,6 +134,10 @@ const props = withDefaults(defineProps<Props>(), {
|
||||
menus: () => []
|
||||
})
|
||||
|
||||
const emit = defineEmits<{
|
||||
(e: 'save-success'): void
|
||||
}>()
|
||||
|
||||
// 转换为菜单树
|
||||
const menuSelectTree = computed(() => {
|
||||
const menus = JSON.parse(JSON.stringify(props.menus)) as MenuResp[]
|
||||
@@ -176,6 +180,7 @@ const { form, resetForm } = useForm<MenuForm>({
|
||||
status: 1
|
||||
})
|
||||
const componentName = computed(() => transformPathToName(form.path))
|
||||
// eslint-disable-next-line vue/return-in-computed-property
|
||||
const formRules = computed(() => {
|
||||
if ([1, 2].includes(form.type)) {
|
||||
const { title, name, path } = rules
|
||||
@@ -239,9 +244,5 @@ const save = async () => {
|
||||
}
|
||||
}
|
||||
|
||||
const emit = defineEmits<{
|
||||
(e: 'save-success'): void
|
||||
}>()
|
||||
|
||||
defineExpose({ onAdd, onUpdate })
|
||||
</script>
|
||||
|
||||
@@ -9,7 +9,7 @@
|
||||
:loading="loading"
|
||||
:scroll="{ x: '100%', y: '100%', minWidth: 1700, maxHeight: '81vh' }"
|
||||
:pagination="false"
|
||||
:disabledColumnKeys="['title']"
|
||||
:disabled-column-keys="['title']"
|
||||
@refresh="search"
|
||||
>
|
||||
<template #expand-icon="{ expanded }">
|
||||
@@ -92,9 +92,9 @@
|
||||
</template>
|
||||
|
||||
<script setup lang="ts">
|
||||
import { listMenu, deleteMenu, type MenuResp, type MenuQuery } from '@/apis'
|
||||
import MenuAddModal from './MenuAddModal.vue'
|
||||
import { Message } from '@arco-design/web-vue'
|
||||
import MenuAddModal from './MenuAddModal.vue'
|
||||
import { type MenuQuery, type MenuResp, deleteMenu, listMenu } from '@/apis'
|
||||
import type GiTable from '@/components/GiTable/index.vue'
|
||||
import type { TableInstanceColumns } from '@/components/GiTable/type'
|
||||
import { DisEnableStatusList } from '@/constant/common'
|
||||
|
||||
@@ -64,13 +64,16 @@
|
||||
</template>
|
||||
|
||||
<script setup lang="ts">
|
||||
import { addNotice, updateNotice, getNotice } from '@/apis'
|
||||
import { Message, type FormInstance } from '@arco-design/web-vue'
|
||||
import { useForm } from '@/hooks'
|
||||
import { useDict } from '@/hooks/app'
|
||||
import { type FormInstance, Message } from '@arco-design/web-vue'
|
||||
import { MdEditor } from 'md-editor-v3'
|
||||
import { useWindowSize } from '@vueuse/core'
|
||||
import { addNotice, getNotice, updateNotice } from '@/apis'
|
||||
import { useForm } from '@/hooks'
|
||||
import { useDict } from '@/hooks/app'
|
||||
|
||||
const emit = defineEmits<{
|
||||
(e: 'save-success'): void
|
||||
}>()
|
||||
const { width } = useWindowSize()
|
||||
const { notice_type } = useDict('notice_type')
|
||||
|
||||
@@ -169,10 +172,6 @@ const save = async () => {
|
||||
}
|
||||
}
|
||||
|
||||
const emit = defineEmits<{
|
||||
(e: 'save-success'): void
|
||||
}>()
|
||||
|
||||
defineExpose({ onAdd, onUpdate })
|
||||
</script>
|
||||
|
||||
|
||||
@@ -23,7 +23,7 @@
|
||||
</a-typography-paragraph>
|
||||
</a-typography>
|
||||
<a-divider />
|
||||
<MdPreview :editorId="dataDetail?.id" :modelValue="dataDetail?.content" />
|
||||
<MdPreview :editor-id="dataDetail?.id" :model-value="dataDetail?.content" />
|
||||
<a-divider />
|
||||
<div v-if="dataDetail?.updateTime" class="update-time-row">
|
||||
<span>
|
||||
@@ -36,9 +36,9 @@
|
||||
</template>
|
||||
|
||||
<script setup lang="ts">
|
||||
import { getNotice, type NoticeResp } from '@/apis'
|
||||
import { MdPreview } from 'md-editor-v3'
|
||||
import { useWindowSize } from '@vueuse/core'
|
||||
import { type NoticeResp, getNotice } from '@/apis'
|
||||
|
||||
const { width } = useWindowSize()
|
||||
const dataDetail = ref<NoticeResp>()
|
||||
|
||||
@@ -9,8 +9,8 @@
|
||||
:loading="loading"
|
||||
:scroll="{ x: '100%', y: '100%', minWidth: 1000 }"
|
||||
:pagination="pagination"
|
||||
:disabledTools="['size']"
|
||||
:disabledColumnKeys="['title']"
|
||||
:disabled-tools="['size']"
|
||||
:disabled-column-keys="['title']"
|
||||
@refresh="search"
|
||||
>
|
||||
<template #custom-left>
|
||||
@@ -58,9 +58,9 @@
|
||||
</template>
|
||||
|
||||
<script lang="ts" setup>
|
||||
import { listNotice, deleteNotice, type NoticeResp, type NoticeQuery } from '@/apis'
|
||||
import NoticeAddModal from './NoticeAddModal.vue'
|
||||
import NoticeDetailModal from './NoticeDetailModal.vue'
|
||||
import { type NoticeQuery, type NoticeResp, deleteNotice, listNotice } from '@/apis'
|
||||
import type { TableInstanceColumns } from '@/components/GiTable/type'
|
||||
import { useTable } from '@/hooks'
|
||||
import { useDict } from '@/hooks/app'
|
||||
@@ -71,6 +71,25 @@ defineOptions({ name: 'SystemNotice' })
|
||||
|
||||
const { notice_type, notice_status_enum } = useDict('notice_type', 'notice_status_enum')
|
||||
|
||||
const queryForm = reactive<NoticeQuery>({
|
||||
sort: ['createTime,desc']
|
||||
})
|
||||
|
||||
const {
|
||||
tableData: dataList,
|
||||
loading,
|
||||
pagination,
|
||||
search,
|
||||
handleDelete
|
||||
} = useTable((p) => listNotice({ ...queryForm, page: p.page, size: p.size }), { immediate: true })
|
||||
|
||||
// 重置
|
||||
const reset = () => {
|
||||
queryForm.title = undefined
|
||||
queryForm.type = undefined
|
||||
search()
|
||||
}
|
||||
|
||||
const columns: TableInstanceColumns[] = [
|
||||
{
|
||||
title: '序号',
|
||||
@@ -95,25 +114,6 @@ const columns: TableInstanceColumns[] = [
|
||||
}
|
||||
]
|
||||
|
||||
const queryForm = reactive<NoticeQuery>({
|
||||
sort: ['createTime,desc']
|
||||
})
|
||||
|
||||
const {
|
||||
tableData: dataList,
|
||||
loading,
|
||||
pagination,
|
||||
search,
|
||||
handleDelete
|
||||
} = useTable((p) => listNotice({ ...queryForm, page: p.page, size: p.size }), { immediate: true })
|
||||
|
||||
// 重置
|
||||
const reset = () => {
|
||||
queryForm.title = undefined
|
||||
queryForm.type = undefined
|
||||
search()
|
||||
}
|
||||
|
||||
// 删除
|
||||
const onDelete = (item: NoticeResp) => {
|
||||
return handleDelete(() => deleteNotice(item.id), {
|
||||
|
||||
@@ -86,12 +86,15 @@
|
||||
</template>
|
||||
|
||||
<script setup lang="ts">
|
||||
import { getRole, addRole, updateRole } from '@/apis'
|
||||
import { Message, type FormInstance, type TreeNodeData } from '@arco-design/web-vue'
|
||||
import { useForm } from '@/hooks'
|
||||
import { useDict, useMenu, useDept } from '@/hooks/app'
|
||||
import { type FormInstance, Message, type TreeNodeData } from '@arco-design/web-vue'
|
||||
import { useWindowSize } from '@vueuse/core'
|
||||
import { addRole, getRole, updateRole } from '@/apis'
|
||||
import { useForm } from '@/hooks'
|
||||
import { useDept, useDict, useMenu } from '@/hooks/app'
|
||||
|
||||
const emit = defineEmits<{
|
||||
(e: 'save-success'): void
|
||||
}>()
|
||||
const { width } = useWindowSize()
|
||||
const { data_scope_enum } = useDict('data_scope_enum')
|
||||
const { deptList, getDeptList } = useDept()
|
||||
@@ -239,10 +242,6 @@ const onCheckAll = (type: string) => {
|
||||
}
|
||||
}
|
||||
|
||||
const emit = defineEmits<{
|
||||
(e: 'save-success'): void
|
||||
}>()
|
||||
|
||||
defineExpose({ onAdd, onUpdate })
|
||||
</script>
|
||||
|
||||
|
||||
@@ -22,7 +22,6 @@
|
||||
>
|
||||
<a-descriptions-item :span="2">
|
||||
<a-tree
|
||||
ref="menuTreeRef"
|
||||
:checked-keys="dataDetail?.menuIds"
|
||||
:data="menuList"
|
||||
default-expand-all
|
||||
@@ -41,7 +40,6 @@
|
||||
>
|
||||
<a-descriptions-item :span="2">
|
||||
<a-tree
|
||||
ref="deptTreeRef"
|
||||
:checked-keys="dataDetail?.deptIds"
|
||||
:data="deptList"
|
||||
default-expand-all
|
||||
@@ -54,9 +52,9 @@
|
||||
</template>
|
||||
|
||||
<script lang="ts" setup>
|
||||
import { getRole, type RoleDetailResp } from '@/apis'
|
||||
import { useDict, useMenu, useDept } from '@/hooks/app'
|
||||
import { useWindowSize } from '@vueuse/core'
|
||||
import { type RoleDetailResp, getRole } from '@/apis'
|
||||
import { useDept, useDict, useMenu } from '@/hooks/app'
|
||||
|
||||
const { width } = useWindowSize()
|
||||
const { data_scope_enum } = useDict('data_scope_enum')
|
||||
|
||||
@@ -8,8 +8,8 @@
|
||||
:loading="loading"
|
||||
:scroll="{ x: '100%', y: '100%', minWidth: 1000 }"
|
||||
:pagination="pagination"
|
||||
:disabledTools="['size']"
|
||||
:disabledColumnKeys="['name']"
|
||||
:disabled-tools="['size']"
|
||||
:disabled-column-keys="['name']"
|
||||
@refresh="search"
|
||||
>
|
||||
<template #custom-left>
|
||||
@@ -57,9 +57,9 @@
|
||||
</template>
|
||||
|
||||
<script setup lang="ts">
|
||||
import { listRole, deleteRole, type RoleResp, type RoleQuery } from '@/apis'
|
||||
import RoleAddModal from './RoleAddModal.vue'
|
||||
import RoleDetailDrawer from './RoleDetailDrawer.vue'
|
||||
import { type RoleQuery, type RoleResp, deleteRole, listRole } from '@/apis'
|
||||
import type { TableInstanceColumns } from '@/components/GiTable/type'
|
||||
import { useTable } from '@/hooks'
|
||||
import { useDict } from '@/hooks/app'
|
||||
@@ -70,6 +70,24 @@ defineOptions({ name: 'SystemRole' })
|
||||
|
||||
const { data_scope_enum } = useDict('data_scope_enum')
|
||||
|
||||
const queryForm = reactive<RoleQuery>({
|
||||
sort: ['createTime,desc']
|
||||
})
|
||||
|
||||
const {
|
||||
tableData: dataList,
|
||||
loading,
|
||||
pagination,
|
||||
search,
|
||||
handleDelete
|
||||
} = useTable((p) => listRole({ ...queryForm, page: p.page, size: p.size }), { immediate: true })
|
||||
|
||||
// 重置
|
||||
const reset = () => {
|
||||
queryForm.description = undefined
|
||||
search()
|
||||
}
|
||||
|
||||
const columns: TableInstanceColumns[] = [
|
||||
{
|
||||
title: '序号',
|
||||
@@ -97,24 +115,6 @@ const columns: TableInstanceColumns[] = [
|
||||
}
|
||||
]
|
||||
|
||||
const queryForm = reactive<RoleQuery>({
|
||||
sort: ['createTime,desc']
|
||||
})
|
||||
|
||||
const {
|
||||
tableData: dataList,
|
||||
loading,
|
||||
pagination,
|
||||
search,
|
||||
handleDelete
|
||||
} = useTable((p) => listRole({ ...queryForm, page: p.page, size: p.size }), { immediate: true })
|
||||
|
||||
// 重置
|
||||
const reset = () => {
|
||||
queryForm.description = undefined
|
||||
search()
|
||||
}
|
||||
|
||||
// 删除
|
||||
const onDelete = (item: RoleResp) => {
|
||||
return handleDelete(() => deleteRole(item.id), { content: `是否确定删除角色 [${item.name}]?`, showModal: true })
|
||||
|
||||
@@ -45,8 +45,8 @@
|
||||
:rules="[
|
||||
{
|
||||
required: true,
|
||||
message: '请输入域名'
|
||||
}
|
||||
message: '请输入域名',
|
||||
},
|
||||
]"
|
||||
>
|
||||
<a-input v-model.trim="form.domain" placeholder="请输入域名" />
|
||||
@@ -88,14 +88,17 @@
|
||||
</template>
|
||||
|
||||
<script setup lang="ts">
|
||||
import { getStorage, addStorage, updateStorage } from '@/apis'
|
||||
import { type FormInstance, Message } from '@arco-design/web-vue'
|
||||
import { useWindowSize } from '@vueuse/core'
|
||||
import type { StorageReq } from './type'
|
||||
import { Message, type FormInstance } from '@arco-design/web-vue'
|
||||
import { addStorage, getStorage, updateStorage } from '@/apis'
|
||||
import { useForm } from '@/hooks'
|
||||
import { useDict } from '@/hooks/app'
|
||||
import { useWindowSize } from '@vueuse/core'
|
||||
import { encryptByRsa } from '@/utils/encrypt'
|
||||
|
||||
const emit = defineEmits<{
|
||||
(e: 'save-success'): void
|
||||
}>()
|
||||
const { width } = useWindowSize()
|
||||
const { storage_type_enum } = useDict('storage_type_enum')
|
||||
|
||||
@@ -175,9 +178,5 @@ const save = async () => {
|
||||
}
|
||||
}
|
||||
|
||||
const emit = defineEmits<{
|
||||
(e: 'save-success'): void
|
||||
}>()
|
||||
|
||||
defineExpose({ onAdd, onUpdate })
|
||||
</script>
|
||||
|
||||
@@ -8,8 +8,8 @@
|
||||
:loading="loading"
|
||||
:scroll="{ x: '100%', y: '100%', minWidth: 1300 }"
|
||||
:pagination="pagination"
|
||||
:disabledTools="['size']"
|
||||
:disabledColumnKeys="['name']"
|
||||
:disabled-tools="['size']"
|
||||
:disabled-column-keys="['name']"
|
||||
@refresh="search"
|
||||
>
|
||||
<template #custom-left>
|
||||
@@ -68,8 +68,8 @@
|
||||
</template>
|
||||
|
||||
<script setup lang="ts">
|
||||
import { listStorage, deleteStorage, type StorageResp, type StorageQuery } from '@/apis'
|
||||
import StorageAddModal from './StorageAddModal.vue'
|
||||
import { type StorageQuery, type StorageResp, deleteStorage, listStorage } from '@/apis'
|
||||
import type { TableInstanceColumns } from '@/components/GiTable/type'
|
||||
import { useTable } from '@/hooks'
|
||||
import { useDict } from '@/hooks/app'
|
||||
@@ -81,6 +81,25 @@ defineOptions({ name: 'SystemStorage' })
|
||||
|
||||
const { storage_type_enum } = useDict('storage_type_enum')
|
||||
|
||||
const queryForm = reactive<StorageQuery>({
|
||||
sort: ['createTime,desc']
|
||||
})
|
||||
|
||||
const {
|
||||
tableData: dataList,
|
||||
loading,
|
||||
pagination,
|
||||
search,
|
||||
handleDelete
|
||||
} = useTable((p) => listStorage({ ...queryForm, page: p.page, size: p.size }), { immediate: true })
|
||||
|
||||
// 重置
|
||||
const reset = () => {
|
||||
queryForm.description = undefined
|
||||
queryForm.status = undefined
|
||||
search()
|
||||
}
|
||||
|
||||
const columns: TableInstanceColumns[] = [
|
||||
{
|
||||
title: '序号',
|
||||
@@ -111,25 +130,6 @@ const columns: TableInstanceColumns[] = [
|
||||
}
|
||||
]
|
||||
|
||||
const queryForm = reactive<StorageQuery>({
|
||||
sort: ['createTime,desc']
|
||||
})
|
||||
|
||||
const {
|
||||
tableData: dataList,
|
||||
loading,
|
||||
pagination,
|
||||
search,
|
||||
handleDelete
|
||||
} = useTable((p) => listStorage({ ...queryForm, page: p.page, size: p.size }), { immediate: true })
|
||||
|
||||
// 重置
|
||||
const reset = () => {
|
||||
queryForm.description = undefined
|
||||
queryForm.status = undefined
|
||||
search()
|
||||
}
|
||||
|
||||
// 删除
|
||||
const onDelete = (item: StorageResp) => {
|
||||
return handleDelete(() => deleteStorage(item.id), { content: `是否确定删除存储 [${item.name}]?`, showModal: true })
|
||||
|
||||
@@ -76,21 +76,24 @@
|
||||
</template>
|
||||
|
||||
<script setup lang="ts">
|
||||
import { getUser, addUser, updateUser } from '@/apis'
|
||||
import { type FormInstance, Message, type TreeNodeData } from '@arco-design/web-vue'
|
||||
import { useWindowSize } from '@vueuse/core'
|
||||
import { addUser, getUser, updateUser } from '@/apis'
|
||||
import type { Gender, Status } from '@/types/global'
|
||||
import { Message, type FormInstance, type TreeNodeData } from '@arco-design/web-vue'
|
||||
import { useForm } from '@/hooks'
|
||||
import { useDept, useRole } from '@/hooks/app'
|
||||
import { useWindowSize } from '@vueuse/core'
|
||||
import { encryptByRsa } from '@/utils/encrypt'
|
||||
|
||||
const emit = defineEmits<{
|
||||
(e: 'save-success'): void
|
||||
}>()
|
||||
const { width } = useWindowSize()
|
||||
const { roleList, getRoleList } = useRole()
|
||||
const { deptList, getDeptList } = useDept()
|
||||
// 过滤部门
|
||||
const filterDeptOptions = (searchKey: string, nodeData: TreeNodeData) => {
|
||||
if (nodeData.title) {
|
||||
return nodeData.title.toLowerCase().indexOf(searchKey.toLowerCase()) > -1
|
||||
return nodeData.title.toLowerCase().includes(searchKey.toLowerCase())
|
||||
}
|
||||
return false
|
||||
}
|
||||
@@ -182,9 +185,5 @@ const save = async () => {
|
||||
}
|
||||
}
|
||||
|
||||
const emit = defineEmits<{
|
||||
(e: 'save-success'): void
|
||||
}>()
|
||||
|
||||
defineExpose({ onAdd, onUpdate })
|
||||
</script>
|
||||
|
||||
@@ -27,8 +27,8 @@
|
||||
</template>
|
||||
|
||||
<script lang="ts" setup>
|
||||
import { getUser, type UserDetailResp } from '@/apis'
|
||||
import { useWindowSize } from '@vueuse/core'
|
||||
import { type UserDetailResp, getUser } from '@/apis'
|
||||
|
||||
const { width } = useWindowSize()
|
||||
|
||||
|
||||
@@ -14,12 +14,15 @@
|
||||
</template>
|
||||
|
||||
<script setup lang="ts">
|
||||
import { resetUserPwd } from '@/apis'
|
||||
import { Message } from '@arco-design/web-vue'
|
||||
import { GiForm, type Columns } from '@/components/GiForm'
|
||||
import { resetUserPwd } from '@/apis'
|
||||
import { type Columns, GiForm } from '@/components/GiForm'
|
||||
import { useForm } from '@/hooks'
|
||||
import { encryptByRsa } from '@/utils/encrypt'
|
||||
|
||||
const emit = defineEmits<{
|
||||
(e: 'save-success'): void
|
||||
}>()
|
||||
const dataId = ref('')
|
||||
const formRef = ref<InstanceType<typeof GiForm>>()
|
||||
|
||||
@@ -65,9 +68,5 @@ const save = async () => {
|
||||
}
|
||||
}
|
||||
|
||||
const emit = defineEmits<{
|
||||
(e: 'save-success'): void
|
||||
}>()
|
||||
|
||||
defineExpose({ onReset })
|
||||
</script>
|
||||
|
||||
@@ -19,15 +19,14 @@
|
||||
</a-col>
|
||||
<a-col :xs="24" :md="20" :lg="20" :xl="20" :xxl="20">
|
||||
<GiTable
|
||||
ref="tableRef"
|
||||
row-key="id"
|
||||
:data="dataList"
|
||||
:columns="columns"
|
||||
:loading="loading"
|
||||
:scroll="{ x: '100%', y: '100%', minWidth: 1500 }"
|
||||
:pagination="pagination"
|
||||
:disabledTools="['size']"
|
||||
:disabledColumnKeys="['username']"
|
||||
:disabled-tools="['size']"
|
||||
:disabled-column-keys="['username']"
|
||||
@refresh="search"
|
||||
>
|
||||
<template #custom-left>
|
||||
@@ -107,13 +106,13 @@
|
||||
</template>
|
||||
|
||||
<script setup lang="ts">
|
||||
import { listUser, deleteUser, exportUser, type UserResp, type UserQuery } from '@/apis'
|
||||
import type { TreeInstance } from '@arco-design/web-vue'
|
||||
import UserAddModal from './UserAddModal.vue'
|
||||
import UserDetailDrawer from './UserDetailDrawer.vue'
|
||||
import UserResetPwdModal from './UserResetPwdModal.vue'
|
||||
import type { TreeInstance } from '@arco-design/web-vue'
|
||||
import { type UserQuery, type UserResp, deleteUser, exportUser, listUser } from '@/apis'
|
||||
import type { TableInstanceColumns } from '@/components/GiTable/type'
|
||||
import { useTable, useDownload } from '@/hooks'
|
||||
import { useDownload, useTable } from '@/hooks'
|
||||
import { useDept } from '@/hooks/app'
|
||||
import { isMobile } from '@/utils'
|
||||
import getAvatar from '@/utils/avatar'
|
||||
@@ -122,6 +121,25 @@ import { DisEnableStatusList } from '@/constant/common'
|
||||
|
||||
defineOptions({ name: 'SystemUser' })
|
||||
|
||||
const queryForm = reactive<UserQuery>({
|
||||
sort: ['createTime,desc']
|
||||
})
|
||||
|
||||
const {
|
||||
tableData: dataList,
|
||||
loading,
|
||||
pagination,
|
||||
search,
|
||||
handleDelete
|
||||
} = useTable((p) => listUser({ ...queryForm, page: p.page, size: p.size }), { immediate: false })
|
||||
|
||||
// 重置
|
||||
const reset = () => {
|
||||
queryForm.description = undefined
|
||||
queryForm.status = undefined
|
||||
search()
|
||||
}
|
||||
|
||||
const columns: TableInstanceColumns[] = [
|
||||
{
|
||||
title: '序号',
|
||||
@@ -160,25 +178,6 @@ const columns: TableInstanceColumns[] = [
|
||||
}
|
||||
]
|
||||
|
||||
const queryForm = reactive<UserQuery>({
|
||||
sort: ['createTime,desc']
|
||||
})
|
||||
|
||||
const {
|
||||
tableData: dataList,
|
||||
loading,
|
||||
pagination,
|
||||
search,
|
||||
handleDelete
|
||||
} = useTable((p) => listUser({ ...queryForm, page: p.page, size: p.size }), { immediate: false })
|
||||
|
||||
// 重置
|
||||
const reset = () => {
|
||||
queryForm.description = undefined
|
||||
queryForm.status = undefined
|
||||
search()
|
||||
}
|
||||
|
||||
// 删除
|
||||
const onDelete = (item: UserResp) => {
|
||||
return handleDelete(() => deleteUser(item.id), {
|
||||
|
||||
@@ -42,8 +42,8 @@
|
||||
:loading="loading"
|
||||
:scroll="{ x: '100%', y: 800, minWidth: 900 }"
|
||||
:pagination="false"
|
||||
:disabledTools="['setting', 'refresh']"
|
||||
:disabledColumnKeys="['tableName']"
|
||||
:disabled-tools="['setting', 'refresh']"
|
||||
:disabled-column-keys="['tableName']"
|
||||
>
|
||||
<template #custom-left>
|
||||
<a-popconfirm
|
||||
@@ -57,7 +57,7 @@
|
||||
status="success"
|
||||
size="small"
|
||||
title="同步"
|
||||
:disabled="dataList.length !== 0 && dataList[0].createTime === null"
|
||||
:disabled="dataList.length !== 0 && dataList[0].createTime == null"
|
||||
>
|
||||
<template #icon><icon-sync /></template>同步
|
||||
</a-button>
|
||||
@@ -111,13 +111,16 @@
|
||||
</template>
|
||||
|
||||
<script setup lang="ts">
|
||||
import { listFieldConfig, getGenConfig, saveGenConfig, type FieldConfigResp, type GeneratorConfigResp } from '@/apis'
|
||||
import { Message, type FormInstance } from '@arco-design/web-vue'
|
||||
import { type FormInstance, Message } from '@arco-design/web-vue'
|
||||
import { useWindowSize } from '@vueuse/core'
|
||||
import { type FieldConfigResp, type GeneratorConfigResp, getGenConfig, listFieldConfig, saveGenConfig } from '@/apis'
|
||||
import type { TableInstanceColumns } from '@/components/GiTable/type'
|
||||
import { useForm } from '@/hooks'
|
||||
import { useDict } from '@/hooks/app'
|
||||
import { useWindowSize } from '@vueuse/core'
|
||||
|
||||
const emit = defineEmits<{
|
||||
(e: 'save-success'): void
|
||||
}>()
|
||||
const { width } = useWindowSize()
|
||||
const { form_type_enum, query_type_enum } = useDict('form_type_enum', 'query_type_enum')
|
||||
|
||||
@@ -208,10 +211,6 @@ const save = async () => {
|
||||
}
|
||||
}
|
||||
|
||||
const emit = defineEmits<{
|
||||
(e: 'save-success'): void
|
||||
}>()
|
||||
|
||||
defineExpose({ onConfig })
|
||||
</script>
|
||||
|
||||
|
||||
@@ -39,9 +39,9 @@
|
||||
</template>
|
||||
|
||||
<script setup lang="ts">
|
||||
import { genPreview, type GeneratePreviewResp, generate } from '@/apis'
|
||||
import { Message, type TreeNodeData } from '@arco-design/web-vue'
|
||||
import { useClipboard } from '@vueuse/core'
|
||||
import { type GeneratePreviewResp, genPreview, generate } from '@/apis'
|
||||
|
||||
const { copy, copied } = useClipboard()
|
||||
const currentPreview = ref<GeneratePreviewResp>()
|
||||
@@ -51,20 +51,35 @@ const visible = ref(false)
|
||||
const treeData = ref<TreeNodeData[]>([])
|
||||
const previewTableName = ref<string>('')
|
||||
|
||||
// 打开
|
||||
const onPreview = async (tableName: string) => {
|
||||
treeData.value = []
|
||||
previewTableName.value = tableName
|
||||
const res = await genPreview(tableName)
|
||||
genPreviewList.value = res.data
|
||||
for (const genPreview of genPreviewList.value) {
|
||||
assembleTree(genPreview)
|
||||
const mergeDir = (parent: TreeNodeData) => {
|
||||
// 合并目录
|
||||
if (parent.children?.length === 1 && typeof parent.children[0].key === 'number') {
|
||||
const mergeTitle = mergeDir(parent.children[0])
|
||||
if (mergeTitle !== '') {
|
||||
parent.title = `${parent.title}/${mergeTitle}`
|
||||
}
|
||||
parent.children = parent.children[0].children
|
||||
return parent.title
|
||||
}
|
||||
for (const valueElement of treeData.value) {
|
||||
mergeDir(valueElement)
|
||||
// 合并子目录
|
||||
if (parent?.children) {
|
||||
for (const child of parent.children) {
|
||||
mergeDir(child)
|
||||
}
|
||||
}
|
||||
currentPreview.value = genPreviewList.value[0]
|
||||
visible.value = true
|
||||
return ''
|
||||
}
|
||||
|
||||
const pushDir = (children: TreeNodeData[] | undefined, treeNode: TreeNodeData) => {
|
||||
if (children) {
|
||||
for (const child of children) {
|
||||
if (child.title === treeNode.title) {
|
||||
return child.children
|
||||
}
|
||||
}
|
||||
}
|
||||
children?.push(treeNode)
|
||||
return treeNode.children
|
||||
}
|
||||
|
||||
// 自增的一个key 因为key相同的节点会出现一些问题
|
||||
@@ -80,35 +95,20 @@ const assembleTree = (genPreview: GeneratePreviewResp) => {
|
||||
tempChildren?.push({ title: genPreview.fileName, key: genPreview.fileName, children: new Array<TreeNodeData>() })
|
||||
}
|
||||
|
||||
const pushDir = (children: TreeNodeData[] | undefined, treeNode: TreeNodeData) => {
|
||||
if (children) {
|
||||
for (const child of children) {
|
||||
if (child.title === treeNode.title) {
|
||||
return child.children
|
||||
}
|
||||
}
|
||||
// 打开
|
||||
const onPreview = async (tableName: string) => {
|
||||
treeData.value = []
|
||||
previewTableName.value = tableName
|
||||
const res = await genPreview(tableName)
|
||||
genPreviewList.value = res.data
|
||||
for (const genPreview of genPreviewList.value) {
|
||||
assembleTree(genPreview)
|
||||
}
|
||||
children?.push(treeNode)
|
||||
return treeNode.children
|
||||
}
|
||||
|
||||
const mergeDir = (parent: TreeNodeData) => {
|
||||
// 合并目录
|
||||
if (parent.children?.length == 1 && typeof parent.children[0].key === 'number') {
|
||||
const mergeTitle = mergeDir(parent.children[0])
|
||||
if (mergeTitle != '') {
|
||||
parent.title = parent.title + '/' + mergeTitle
|
||||
}
|
||||
parent.children = parent.children[0].children
|
||||
return parent.title
|
||||
for (const valueElement of treeData.value) {
|
||||
mergeDir(valueElement)
|
||||
}
|
||||
// 合并子目录
|
||||
if (parent?.children) {
|
||||
for (const child of parent.children) {
|
||||
mergeDir(child)
|
||||
}
|
||||
}
|
||||
return ''
|
||||
currentPreview.value = genPreviewList.value[0]
|
||||
visible.value = true
|
||||
}
|
||||
|
||||
// 选择文件预览
|
||||
@@ -134,7 +134,7 @@ watch(copied, () => {
|
||||
const onGenerate = async () => {
|
||||
const res = await generate([previewTableName.value])
|
||||
const contentDisposition = res.headers['content-disposition']
|
||||
const pattern = new RegExp('filename=([^;]+\\.[^\.;]+);*')
|
||||
const pattern = /filename=([^;]+\.[^.;]+);*/
|
||||
const result = pattern.exec(contentDisposition) || ''
|
||||
// 对名字进行解码
|
||||
const fileName = window.decodeURI(result[1])
|
||||
|
||||
@@ -8,8 +8,8 @@
|
||||
:loading="loading"
|
||||
:scroll="{ x: '100%', y: '100%', minWidth: 1000 }"
|
||||
:pagination="pagination"
|
||||
:disabledTools="['size', 'setting']"
|
||||
:disabledColumnKeys="['tableName']"
|
||||
:disabled-tools="['size', 'setting']"
|
||||
:disabled-column-keys="['tableName']"
|
||||
@refresh="search"
|
||||
>
|
||||
<template #custom-left>
|
||||
@@ -25,8 +25,9 @@
|
||||
:title="record.isConfiged ? '生成' : '请先进行生成配置'"
|
||||
:disabled="!record.isConfiged"
|
||||
@click="onPreview(record.tableName)"
|
||||
>生成</a-link
|
||||
>
|
||||
生成
|
||||
</a-link>
|
||||
</a-space>
|
||||
</template>
|
||||
</GiTable>
|
||||
@@ -38,15 +39,27 @@
|
||||
</template>
|
||||
|
||||
<script setup lang="ts">
|
||||
import { listGenerator } from '@/apis'
|
||||
import GenConfigDrawer from './GenConfigDrawer.vue'
|
||||
import GenPreviewModal from './GenPreviewModal.vue'
|
||||
import { listGenerator } from '@/apis'
|
||||
import type { TableInstanceColumns } from '@/components/GiTable/type'
|
||||
import { useTable } from '@/hooks'
|
||||
import { isMobile } from '@/utils'
|
||||
|
||||
defineOptions({ name: 'Generator' })
|
||||
|
||||
const queryForm = reactive({
|
||||
tableName: undefined,
|
||||
sort: ['createTime,desc']
|
||||
})
|
||||
|
||||
const {
|
||||
tableData: dataList,
|
||||
loading,
|
||||
pagination,
|
||||
search
|
||||
} = useTable((p) => listGenerator({ ...queryForm, page: p.page, size: p.size }), { immediate: true })
|
||||
|
||||
const columns: TableInstanceColumns[] = [
|
||||
{
|
||||
title: '序号',
|
||||
@@ -62,18 +75,6 @@ const columns: TableInstanceColumns[] = [
|
||||
{ title: '操作', slotName: 'action', width: 180, align: 'center', fixed: !isMobile() ? 'right' : undefined }
|
||||
]
|
||||
|
||||
const queryForm = reactive({
|
||||
tableName: undefined,
|
||||
sort: ['createTime,desc']
|
||||
})
|
||||
|
||||
const {
|
||||
tableData: dataList,
|
||||
loading,
|
||||
pagination,
|
||||
search
|
||||
} = useTable((p) => listGenerator({ ...queryForm, page: p.page, size: p.size }), { immediate: true })
|
||||
|
||||
// 重置
|
||||
const reset = () => {
|
||||
queryForm.tableName = undefined
|
||||
|
||||
Reference in New Issue
Block a user