feat: 前端表格高级筛选 (#100)

* chore: 🔨 css 基础单位

[skip ci]

* fix: 🐛 ca2263 System.Enum.GetValues<TEnum>()

[skip ci]

* feat:  前端表格高级筛选

[skip ci]
This commit is contained in:
2024-04-22 21:16:53 +08:00
committed by GitHub
parent 1dc953a2b2
commit 3847d6fdbb
175 changed files with 1901 additions and 630 deletions

View File

@ -11,38 +11,41 @@
"dependencies": {
"@element-plus/icons-vue": "^2.3.1",
"@tinymce/tinymce-vue": "^5.1.1",
"axios": "^1.6.7",
"ace-builds": "^1.33.0",
"axios": "^1.6.8",
"clipboard": "^2.0.11",
"core-js": "^3.36.0",
"core-js": "^3.37.0",
"cropperjs": "^1.6.1",
"crypto-js": "^4.2.0",
"echarts": "^5.5.0",
"element-plus": "^2.6.1",
"element-plus": "^2.7.0",
"json-bigint": "^1.0.0",
"json5-to-table": "^0.1.8",
"markdown-it": "^14.0.0",
"markdown-it": "^14.1.0",
"markdown-it-emoji": "^3.0.0",
"nprogress": "^0.2.0",
"pinyin-match": "^1.2.5",
"qrcodejs2": "^0.0.2",
"sortablejs": "^1.15.2",
"tinymce": "^6.8.3",
"vue": "^3.4.21",
"vue-i18n": "^9.10.1",
"vue-router": "^4.3.0",
"vkbeautify": "^0.99.3",
"vue": "^3.4.23",
"vue-i18n": "^9.12.1",
"vue-router": "^4.3.1",
"vue3-ace-editor": "^2.2.4",
"vue3-json-viewer": "^2.2.2",
"vuedraggable": "^4.0.3",
"vuex": "^4.1.0",
"xgplayer": "^3.0.14",
"xgplayer-hls": "^3.0.14"
"xgplayer": "^3.0.16",
"xgplayer-hls": "^3.0.16"
},
"devDependencies": {
"@vitejs/plugin-vue": "^5.0.4",
"prettier": "^3.2.5",
"prettier-plugin-organize-attributes": "^1.0.0",
"sass": "^1.71.1",
"terser": "^5.29.1",
"vite": "^5.1.5"
"sass": "^1.75.0",
"terser": "^5.30.3",
"vite": "^5.2.9"
},
"browserslist": [
"> 1%",

View File

@ -1,6 +1,6 @@
<template>
<el-config-provider :button="config.button" :locale="locale" :size="config.size" :zIndex="config.zIndex">
<router-view></router-view>
<router-view v-if="isRouterAlive"></router-view>
</el-config-provider>
</template>
@ -9,8 +9,14 @@ import colorTool from '@/utils/color'
export default {
name: 'App',
provide() {
return {
reload: this.reload,
}
},
data() {
return {
isRouterAlive: true,
config: {
size: 'default',
zIndex: 2000,
@ -25,6 +31,14 @@ export default {
return this.$i18n.messages[this.$i18n.locale].el
},
},
methods: {
reload() {
this.isRouterAlive = false
this.$nextTick(function () {
this.isRouterAlive = true
})
},
},
async created() {
//设置主题颜色
const app_color = this.$TOOL.data.get('APP_COLOR') ?? this.$CONFIG.COLOR

View File

@ -0,0 +1,18 @@
/**
* 探针组件
* @module @/api/probe
*/
import config from '@/config'
import http from '@/utils/request'
export default {
/**
* 健康检查
*/
healthCheck: {
url: `${config.API_URL}/api/probe/health.check`,
name: `健康检查`,
get: async function (data = {}, config = {}) {
return await http.get(this.url, data, config)
},
},
}

View File

@ -5,6 +5,17 @@
import config from '@/config'
import http from '@/utils/request'
export default {
/**
* 接口计数
*/
count: {
url: `${config.API_URL}/api/sys/api/count`,
name: `接口计数`,
post: async function (data = {}, config = {}) {
return await http.post(this.url, data, config)
},
},
/**
* 查询接口
*/

View File

@ -16,6 +16,17 @@ export default {
},
},
/**
* 配置计数
*/
count: {
url: `${config.API_URL}/api/sys/config/count`,
name: `配置计数`,
post: async function (data = {}, config = {}) {
return await http.post(this.url, data, config)
},
},
/**
* 创建配置
*/

View File

@ -16,6 +16,17 @@ export default {
},
},
/**
* 部门计数
*/
count: {
url: `${config.API_URL}/api/sys/dept/count`,
name: `部门计数`,
post: async function (data = {}, config = {}) {
return await http.post(this.url, data, config)
},
},
/**
* 创建部门
*/

View File

@ -16,6 +16,17 @@ export default {
},
},
/**
* 计划作业计数
*/
count: {
url: `${config.API_URL}/api/sys/job/count`,
name: `计划作业计数`,
post: async function (data = {}, config = {}) {
return await http.post(this.url, data, config)
},
},
/**
* 创建计划作业
*/

View File

@ -5,6 +5,17 @@
import config from '@/config'
import http from '@/utils/request'
export default {
/**
* 请求日志计数
*/
count: {
url: `${config.API_URL}/api/sys/log/count`,
name: `请求日志计数`,
post: async function (data = {}, config = {}) {
return await http.post(this.url, data, config)
},
},
/**
* 获取单个请求日志
*/

View File

@ -16,6 +16,17 @@ export default {
},
},
/**
* 菜单计数
*/
count: {
url: `${config.API_URL}/api/sys/menu/count`,
name: `菜单计数`,
post: async function (data = {}, config = {}) {
return await http.post(this.url, data, config)
},
},
/**
* 创建菜单
*/

View File

@ -16,6 +16,17 @@ export default {
},
},
/**
* 角色计数
*/
count: {
url: `${config.API_URL}/api/sys/role/count`,
name: `角色计数`,
post: async function (data = {}, config = {}) {
return await http.post(this.url, data, config)
},
},
/**
* 创建角色
*/

View File

@ -16,6 +16,17 @@ export default {
},
},
/**
* 站内信计数
*/
count: {
url: `${config.API_URL}/api/sys/site.msg/count`,
name: `站内信计数`,
post: async function (data = {}, config = {}) {
return await http.post(this.url, data, config)
},
},
/**
* 创建站内信
*/

View File

@ -27,6 +27,17 @@ export default {
},
},
/**
* 用户计数
*/
count: {
url: `${config.API_URL}/api/sys/user/count`,
name: `用户计数`,
post: async function (data = {}, config = {}) {
return await http.post(this.url, data, config)
},
},
/**
* 创建用户
*/

View File

@ -5,6 +5,17 @@
import config from '@/config'
import http from '@/utils/request'
export default {
/**
* 验证码计数
*/
count: {
url: `${config.API_URL}/api/sys/verify.code/count`,
name: `验证码计数`,
post: async function (data = {}, config = {}) {
return await http.post(this.url, data, config)
},
},
/**
* 发送验证码
*/

View File

@ -16,6 +16,17 @@ export default {
},
},
/**
* 示例计数
*/
count: {
url: `${config.API_URL}/api/tpl/example/count`,
name: `示例计数`,
post: async function (data = {}, config = {}) {
return await http.post(this.url, data, config)
},
},
/**
* 创建示例
*/

View File

@ -1,7 +1,7 @@
<template>
<svg class="icon" height="128" p-id="4181" t="1695638866565" version="1.1" viewBox="0 0 1024 1024" width="128" xmlns="http://www.w3.org/2000/svg">
<svg class="icon" height="128" p-id="4416" t="1711433117657" version="1.1" viewBox="0 0 1024 1024" width="128" xmlns="http://www.w3.org/2000/svg">
<path
d="M512 97.52381c228.912762 0 414.47619 185.563429 414.47619 414.47619s-185.563429 414.47619-414.47619 414.47619S97.52381 740.912762 97.52381 512 283.087238 97.52381 512 97.52381z m129.29219 233.447619l-129.267809 129.29219-129.316571-129.29219-51.736381 51.736381 129.316571 129.267809-129.316571 129.316571 51.736381 51.736381L512 563.687619l129.29219 129.316571 51.736381-51.73638L563.687619 512l129.316571-129.29219-51.73638-51.736381z"
p-id="4182"></path>
d="M896 512a384 384 0 1 0-768 0 384 384 0 0 0 768 0zM42.666667 512C42.666667 252.8 252.8 42.666667 512 42.666667s469.333333 210.133333 469.333333 469.333333-210.133333 469.333333-469.333333 469.333333S42.666667 771.2 42.666667 512z m469.333333 60.330667l-140.501333 140.501333-60.330667-60.330667L451.669333 512 311.168 371.498667l60.330667-60.330667L512 451.669333l140.501333-140.501333 60.330667 60.330667L572.330667 512l140.501333 140.501333-60.330667 60.330667L512 572.330667z"
p-id="4417"></path>
</svg>
</template>

View File

@ -0,0 +1,7 @@
<template>
<svg class="icon" height="128" p-id="4316" t="1711351919517" version="1.1" viewBox="0 0 1024 1024" width="128" xmlns="http://www.w3.org/2000/svg">
<path
d="M512 58.496a453.504 453.504 0 1 0 0 907.008 453.504 453.504 0 0 0 0-907.008zM512 0a512 512 0 1 1 0 1024A512 512 0 0 1 512 0zM387.648 434.752H328v-13.44a63.744 63.744 0 0 0-9.664-35.392c-6.4-9.984-17.28-14.912-32.512-14.912a37.568 37.568 0 0 0-19.84 4.672 39.232 39.232 0 0 0-12.352 11.712 49.472 49.472 0 0 0-6.4 17.28 112.64 112.64 0 0 0-1.792 20.16c0 8.192 0.32 14.976 0.896 20.48 0.64 5.44 2.048 10.304 4.416 14.592 2.304 4.288 5.76 8 10.24 11.136 4.48 3.136 10.624 6.272 18.432 9.344l45.632 18.176c13.248 5.056 24 11.008 32.192 17.856 8.192 6.784 14.592 14.72 19.264 23.68 4.288 9.344 7.232 19.968 8.832 31.872 1.536 11.904 2.304 25.472 2.304 40.704 0 17.536-1.728 33.792-5.248 48.832a102.912 102.912 0 0 1-16.96 38.336c-8.192 10.88-18.944 19.52-32.192 25.728-13.248 6.272-29.44 9.344-48.576 9.344a106.24 106.24 0 0 1-40.32-7.552 96 96 0 0 1-32.256-21.12 102.528 102.528 0 0 1-21.312-31.296 95.04 95.04 0 0 1-7.936-38.912v-22.208h59.712v18.688c0 10.944 3.2 20.8 9.6 29.568 6.464 8.768 17.28 13.184 32.512 13.184a52.352 52.352 0 0 0 23.68-4.416 31.488 31.488 0 0 0 13.184-12.544 46.208 46.208 0 0 0 5.568-19.648 334.336 334.336 0 0 0-0.32-52.352 46.336 46.336 0 0 0-4.672-16.96 32.896 32.896 0 0 0-10.816-10.56 138.688 138.688 0 0 0-17.856-8.768l-42.688-17.536c-25.792-10.56-43.008-24.448-51.84-41.856-8.768-17.344-13.12-39.04-13.12-65.28 0-15.552 2.112-30.4 6.4-44.416a101.12 101.12 0 0 1 19.328-36.288c8.192-10.112 18.624-18.24 31.36-24.32 12.608-6.016 27.776-9.024 45.312-9.024 14.784 0 28.352 2.752 40.64 8.192s22.912 12.672 31.936 21.632c17.92 18.752 26.88 40.192 26.88 64.384v29.248z m100.672 198.4c0 14.4 3.968 25.024 11.968 31.872 8 6.848 17.472 10.24 28.416 10.24a29.184 29.184 0 0 0 12.8-2.368l-26.88-21.632 30.464-36.288 23.936 19.328V413.12c0-14.464-3.968-25.088-11.968-31.872a42.304 42.304 0 0 0-28.352-10.24 42.304 42.304 0 0 0-28.416 10.24c-8 6.784-11.968 17.408-11.968 31.872v220.032zM428.608 413.12c0-16.768 2.944-31.616 8.768-44.48a93.952 93.952 0 0 1 55.296-50.88c11.904-4.288 23.936-6.464 36.032-6.464a106.048 106.048 0 0 1 68.48 25.152c9.344 8.576 16.896 19.328 22.784 32.192 5.824 12.864 8.768 27.712 8.768 44.48v220.032c0 16.384-2.944 30.592-8.768 42.688l36.864 29.824-30.464 36.288-35.072-28.672c-17.92 14.464-38.848 21.632-62.592 21.632-12.16 0-24.128-2.112-36.032-6.4a93.888 93.888 0 0 1-31.872-19.328 89.344 89.344 0 0 1-23.424-30.976 105.472 105.472 0 0 1-8.768-45.056V413.12z m252.8 318.336v-416.64h59.648v356.928h118.208v59.712h-177.92z"
p-id="4317"></path>
</svg>
</template>

View File

@ -0,0 +1,7 @@
<template>
<svg class="icon" height="128" p-id="4455" t="1711352616562" version="1.1" viewBox="0 0 1024 1024" width="128" xmlns="http://www.w3.org/2000/svg">
<path
d="M128 161.066667v701.866666c0 18.24 14.826667 33.066667 33.066667 33.066667h701.866666c18.24 0 33.066667-14.826667 33.066667-33.066667V161.066667c0-18.24-14.826667-33.066667-33.066667-33.066667H161.066667c-18.24 0-33.066667 14.826667-33.066667 33.066667z m64 670.933333V640h96c12.16 0 23.253333-6.826667 28.586667-17.706667l31.146666-62.4 70.186667 187.306667c4.693333 12.586667 16.746667 20.8 29.973333 20.8 0.746667 0 1.6 0 2.346667-0.106667 14.186667-1.066667 25.92-11.306667 28.906667-25.173333l69.866666-326.08 60.16 200.64c3.733333 12.586667 14.826667 21.546667 27.946667 22.72 13.12 1.173333 25.493333-5.866667 31.36-17.6L723.733333 512H832v320H192z m640-640v256H704c-12.16 0-23.253333 6.826667-28.586667 17.706667L647.466667 521.493333l-72.853334-242.666666c-4.16-13.973333-17.386667-23.36-31.893333-22.826667-14.613333 0.64-26.986667 10.986667-29.973333 25.28l-73.066667 341.226667-57.6-153.706667c-4.48-11.946667-15.573333-20.053333-28.266667-20.693333-12.693333-0.64-24.64 6.293333-30.293333 17.6L268.266667 576H192V192h640z"
p-id="4456"></path>
</svg>
</template>

View File

@ -0,0 +1,7 @@
<template>
<svg class="icon" height="128" p-id="4342" t="1711592650939" version="1.1" viewBox="0 0 1024 1024" width="128" xmlns="http://www.w3.org/2000/svg">
<path
d="M832 665.6v-164.266667c0-17.066667-14.933333-32-32-32h-256v-128H789.333333c23.466667 0 42.666667-19.2 42.666667-42.666666V149.333333c0-23.466667-19.2-42.666667-42.666667-42.666666H234.666667c-23.466667 0-42.666667 19.2-42.666667 42.666666v149.333334c0 23.466667 19.2 42.666667 42.666667 42.666666h245.333333v128h-256c-17.066667 0-32 14.933333-32 32v164.266667c-55.466667 14.933333-96 64-96 123.733333 0 70.4 57.6 128 128 128s128-57.6 128-128c0-59.733333-40.533333-108.8-96-123.733333V533.333333h224v132.266667c-55.466667 14.933333-96 64-96 123.733333 0 70.4 57.6 128 128 128s128-57.6 128-128c0-59.733333-40.533333-108.8-96-123.733333V533.333333H768v132.266667c-55.466667 14.933333-96 64-96 123.733333 0 70.4 57.6 128 128 128s128-57.6 128-128c0-59.733333-40.533333-108.8-96-123.733333zM256 170.666667h512v106.666666H256V170.666667z m32 618.666666c0 36.266667-27.733333 64-64 64s-64-27.733333-64-64 27.733333-64 64-64 64 27.733333 64 64zM576 789.333333c0 36.266667-27.733333 64-64 64s-64-27.733333-64-64 27.733333-64 64-64 64 27.733333 64 64z m224 64c-36.266667 0-64-27.733333-64-64s27.733333-64 64-64 64 27.733333 64 64-27.733333 64-64 64z"
p-id="4343"></path>
</svg>
</template>

View File

@ -63,4 +63,7 @@ export { default as Help } from './Help.vue'
export { default as Version } from './Version.vue'
export { default as Home } from './Home.vue'
export { default as Exception } from './Exception.vue'
export { default as Collect } from './Collect.vue'
export { default as Collect } from './Collect.vue'
export { default as FreeSql } from './FreeSql.vue'
export { default as Performance } from './Performance.vue'
export { default as Proxy } from './Proxy.vue'

View File

@ -15,14 +15,6 @@
</template>
</el-table-column>
</template>
<style scoped>
.indicator {
display: flex;
align-items: center;
justify-content: center;
gap: 0.5rem;
}
</style>
<script>
import tool from '@/utils/tool'

View File

@ -1,9 +1,9 @@
<template>
<el-table-column :label="$t('操作')" align="right">
<el-table-column align="right">
<template #default="scope">
<el-button-group>
<template v-for="(item, i) in buttons?.filter((x) => !x.condition || x.condition(scope))" :key="i">
<el-popconfirm v-if="item.confirm" :title="`确定${item.title}`" @confirm="item.click(scope.row, vue)">
<el-popconfirm v-if="item.confirm" :title="`确定${item.title}`" @confirm="item.click(scope.row, vue)" width="200">
<template #reference>
<el-button :icon="item.icon" :title="item.title" :type="item.type" @click.native.stop size="small"></el-button>
</template>

View File

@ -1,16 +1,28 @@
<template>
<el-table-column v-bind="$attrs">
<template #default="scope">
<div @click="click(tool.getNestedProperty(scope.row, $attrs.prop))" class="avatar" style="cursor: pointer">
<div @click="click(tool.getNestedProperty(scope.row, $attrs.prop))" class="avatar">
<el-avatar v-if="tool.getNestedProperty(scope.row, $attrs.nestProp)" :src="getAvatar(scope)" size="small"></el-avatar>
<el-text tag="ins">{{ tool.getNestedProperty(scope.row, $attrs.nestProp) }}</el-text>
<div>
<p>{{ tool.getNestedProperty(scope.row, $attrs.nestProp) }}</p>
<p v-if="$attrs.nestProp2">{{ tool.getNestedProperty(scope.row, $attrs.nestProp2) }}</p>
</div>
</div>
<save-dialog v-if="dialog.save" @closed="dialog.save = false" ref="saveDialog"></save-dialog>
</template>
</el-table-column>
</template>
<style scoped>
<style lang="scss" scoped>
.avatar {
div:last-child {
line-height: 1rem;
p:last-child {
color: var(--el-color-info-light-3);
}
}
justify-content: center;
align-items: center;
cursor: pointer;
display: flex;
gap: 0.5rem;
}

View File

@ -4,76 +4,13 @@
v-if="hasDate"
v-model="form.dy.createdTime"
:end-placeholder="$t('结束日期')"
:format="dateFormat"
:range-separator="$t('至')"
:shortcuts="[
{
text: '今天',
value: () => {
const start = new Date()
return [start, start]
},
},
{
text: '昨天',
value: () => {
const start = new Date()
start.setTime(new Date().getTime() - 3600 * 1000 * 24)
return [start, start]
},
},
{
text: '最近三天',
value: () => {
const start = new Date()
start.setTime(start.getTime() - 3600 * 1000 * 24 * 3)
return [start, new Date()]
},
},
{
text: '最近一周',
value: () => {
const start = new Date()
start.setTime(start.getTime() - 3600 * 1000 * 24 * 7)
return [start, new Date()]
},
},
{
text: '最近一月',
value: () => {
const start = new Date()
start.setMonth(start.getMonth() - 1)
return [start, new Date()]
},
},
{
text: '最近三月',
value: () => {
const start = new Date()
start.setMonth(start.getMonth() - 3)
return [start, new Date()]
},
},
{
text: '最近六月',
value: () => {
const start = new Date()
start.setMonth(start.getMonth() - 6)
return [start, new Date()]
},
},
{
text: '最近一年',
value: () => {
const start = new Date()
start.setFullYear(start.getFullYear() - 1)
return [start, new Date()]
},
},
]"
:shortcuts="dateShortCuts"
:start-placeholder="$t('开始日期')"
:teleported="false"
type="daterange"
value-format="YYYY-MM-DD"></el-date-picker>
:type="dateType"
:value-format="dateValueFormat"></el-date-picker>
<template v-for="(item, i) in controls" :key="i">
<el-input
@ -120,25 +57,269 @@
clearable
filterable />
</template>
<el-button-group>
<el-button @click="search" icon="el-icon-search" type="primary">查询</el-button>
<el-button @click="reset" icon="el-icon-refresh-left">重置</el-button>
</el-button-group>
<el-badge :hidden="vue.query.dynamicFilter.filters.length === 0" :value="vue.query.dynamicFilter.filters.length">
<el-button-group>
<el-button @click="search" icon="el-icon-search" type="primary">查询</el-button>
<el-popover :title="$t('已应用的查询条件')" placement="bottom-end" trigger="hover" width="40rem">
<template #reference>
<el-button @click="reset" icon="el-icon-refresh-left">重置</el-button>
</template>
<v-ace-editor
:theme="this.$TOOL.data.get('APP_DARK') ? 'github_dark' : 'github'"
:value="vkbeautify().json(vue.query, 2)"
lang="json"
style="height: 20rem; width: 100%" />
</el-popover>
</el-button-group>
</el-badge>
</form>
</template>
<style scoped></style>
<script>
import tool from '@/utils/tool'
import vkbeautify from 'vkbeautify/index'
export default {
emits: ['search'],
props: {
hasDate: { type: Boolean, default: true },
dateType: { type: String, default: 'daterange' },
dateFormat: { type: String, default: 'YYYY-MM-DD' },
dateValueFormat: { type: String, default: 'YYYY-MM-DD' },
controls: { type: Array },
vue: { type: Object },
},
data() {
return {
dateShortCuts: [
{
text: '今天',
value: () => {
const start = new Date()
start.setHours(0, 0, 0, 0)
return [start, start]
},
},
{
text: '昨天',
value: () => {
const start = new Date()
start.setHours(0, 0, 0, 0)
start.setTime(start.getTime() - 3600 * 1000 * 24)
return [start, start]
},
},
{
text: '最近三天',
value: () => {
const start = new Date()
start.setHours(0, 0, 0, 0)
start.setTime(start.getTime() - 3600 * 1000 * 24 * 2)
const end = new Date()
end.setHours(0, 0, 0, 0)
return [start, end]
},
},
{
text: '最近一周',
value: () => {
const start = new Date()
start.setHours(0, 0, 0, 0)
start.setTime(start.getTime() - 3600 * 1000 * 24 * 6)
const end = new Date()
end.setHours(0, 0, 0, 0)
return [start, end]
},
},
{
text: '最近一月',
value: () => {
const start = new Date()
start.setHours(0, 0, 0, 0)
start.setMonth(start.getMonth() - 1)
const end = new Date()
end.setHours(0, 0, 0, 0)
return [start, end]
},
},
{
text: '最近三月',
value: () => {
const start = new Date()
start.setHours(0, 0, 0, 0)
start.setMonth(start.getMonth() - 3)
const end = new Date()
end.setHours(0, 0, 0, 0)
return [start, end]
},
},
{
text: '最近六月',
value: () => {
const start = new Date()
start.setHours(0, 0, 0, 0)
start.setMonth(start.getMonth() - 6)
const end = new Date()
end.setHours(0, 0, 0, 0)
return [start, end]
},
},
{
text: '最近一年',
value: () => {
const start = new Date()
start.setHours(0, 0, 0, 0)
start.setFullYear(start.getFullYear() - 1)
const end = new Date()
end.setHours(0, 0, 0, 0)
return [start, end]
},
},
],
options: [
{
label: '订单号',
value: 'id',
type: 'text',
selected: true,
placeholder: '请输入订单号',
},
{
label: '类型',
value: 'type',
type: 'select',
operator: '=',
selected: true,
placeholder: '请选择类型',
extend: {
data: [
{
label: '选项1',
value: '1',
},
{
label: '选项2',
value: '2',
},
],
},
},
{
label: '类型(多选)',
value: 'type2',
type: 'select',
operator: '=',
placeholder: '请选择类型',
extend: {
multiple: true,
data: [
{
label: '选项1',
value: '1',
},
{
label: '选项2',
value: '2',
},
],
},
},
{
label: '通知(异步)',
value: 'noticeType',
type: 'select',
operator: '=',
placeholder: '请选择通知类型',
extend: {
request: async () => {
const list = await this.$API.system.dic.get.get()
return list.data.map((item) => {
return {
label: item.label,
value: item.value,
}
})
},
},
},
{
label: '通知(远程搜索)',
value: 'noticeType2',
type: 'select',
operator: '=',
placeholder: '请输入关键词后检索',
extend: {
remote: true,
request: async (query) => {
var data = {
keyword: query,
}
var list = await this.$API.system.dic.get.get(data)
return list.data.map((item) => {
return {
label: item.label,
value: item.value,
}
})
},
},
},
{
label: '关键词(标签)',
value: 'tags',
type: 'tags',
operator: 'include',
operators: [
{
label: '包含',
value: 'include',
},
{
label: '不包含',
value: 'notinclude',
},
],
},
{
label: '开关(可重复)',
value: 'switch',
type: 'switch',
repeat: true,
operator: '=',
},
{
label: '日期单选',
value: 'date',
type: 'date',
operator: '=',
operators: [
{
label: '等于',
value: '=',
},
{
label: '不等于',
value: '!=',
},
],
},
{
label: '日期范围',
value: 'date2',
type: 'daterange',
},
{
label: '自定义日期',
value: 'date3',
type: 'customDate',
placeholder: '请选择月份',
extend: {
dateType: 'month',
valueFormat: 'YYYY-MM',
},
},
],
casLoaded: false,
keepKeywords: null,
form: {
@ -150,6 +331,28 @@ export default {
},
mounted() {},
async created() {
if (this.dateType === 'datetimerange') {
this.dateShortCuts.unshift(
{
text: '最近一时',
value: () => {
const start = new Date()
const end = new Date()
start.setTime(start.getTime() - 3600 * 1000)
return [start, end]
},
},
{
text: '昨日此时',
value: () => {
return [
new Date(new Date(new Date().getTime() - 86400 * 1000).setHours(0, 0, 0, 0)),
new Date(new Date().getTime() - 86400 * 1000),
]
},
},
)
}
this.controls
.filter((x) => x.type === 'cascader')
.forEach((x) => {
@ -160,13 +363,15 @@ export default {
}
this.casLoaded = true
},
components: {},
computed: {
tool() {
return tool
},
},
methods: {
vkbeautify() {
return vkbeautify
},
search() {
const parentQuery = this.clearParentQuery()
Object.assign(parentQuery, this.form.root || {})

View File

@ -23,6 +23,7 @@
:summary-method="remoteSummary ? remoteSummaryMethod : summaryMethod"
@cell-click="cellClickMethod"
@filter-change="filterChange"
@row-contextmenu="rowContextmenu"
@sort-change="sortChange"
ref="scTable">
<slot></slot>
@ -108,17 +109,63 @@
</div>
</div>
</div>
<sc-contextmenu @command="contextMenuCommand" @visible-change="contextMenuVisibleChange" ref="contextmenu">
<sc-contextmenu-item
v-for="(menu, index) in contextMenus"
:command="menu"
:disabled="menu !== current.column.property"
:key="index"
:title="`${menu}`">
<sc-contextmenu-item :command="`${menu}^|^Equal^|^${current.row[menu]}`" title="="></sc-contextmenu-item>
<sc-contextmenu-item :command="`${menu}^|^NotEqual^|^${current.row[menu]}`" title="≠"></sc-contextmenu-item>
<sc-contextmenu-item :command="`${menu}^|^GreaterThan^|^${current.row[menu]}`" divided title=""></sc-contextmenu-item>
<sc-contextmenu-item :command="`${menu}^|^GreaterThanOrEqual^|^${current.row[menu]}`" title="≥"></sc-contextmenu-item>
<sc-contextmenu-item :command="`${menu}^|^LessThan^|^${current.row[menu]}`" title=""></sc-contextmenu-item>
<sc-contextmenu-item :command="`${menu}^|^LessThanOrEqual^|^${current.row[menu]}`" title="≤"></sc-contextmenu-item>
<sc-contextmenu-item :command="`${menu}^|^Contains^|^${current.row[menu]}`" divided title="包含"></sc-contextmenu-item>
<sc-contextmenu-item :command="`${menu}^|^NotContains^|^${current.row[menu]}`" title="不含"></sc-contextmenu-item>
<sc-contextmenu-item :command="`${menu}^|^StartsWith^|^${current.row[menu]}`" divided title="以 x 开始"></sc-contextmenu-item>
<sc-contextmenu-item :command="`${menu}^|^NotStartsWith^|^${current.row[menu]}`" title="非 x 开始"></sc-contextmenu-item>
<sc-contextmenu-item :command="`${menu}^|^EndsWith^|^${current.row[menu]}`" title="以 x 结束"></sc-contextmenu-item>
<sc-contextmenu-item :command="`${menu}^|^NotEndsWith^|^${current.row[menu]}`" title="非 x 结束"></sc-contextmenu-item>
<sc-contextmenu-item :command="`${menu}^|^Range^|^${current.row[menu]}`" divided title="数值范围"></sc-contextmenu-item>
<sc-contextmenu-item :command="`${menu}^|^DateRange^|^${current.row[menu]}`" title="日期范围"></sc-contextmenu-item>
<sc-contextmenu-item :command="`${menu}^|^Any^|^${current.row[menu]}`" divided title="为其一"></sc-contextmenu-item>
<sc-contextmenu-item :command="`${menu}^|^NotAny^|^${current.row[menu]}`" title="非其一"></sc-contextmenu-item>
</sc-contextmenu-item>
<sc-contextmenu-item v-if="contextOpers.includes('view')" command="view" divided icon="el-icon-view" title="查看"></sc-contextmenu-item>
<sc-contextmenu-item v-if="contextOpers.includes('edit')" command="edit" icon="el-icon-edit" title="编辑"></sc-contextmenu-item>
<sc-contextmenu-item v-if="contextOpers.includes('del')" command="del" icon="el-icon-delete" title="删除"></sc-contextmenu-item>
<sc-contextmenu-item
v-for="(adv, index) in contextAdvs"
:command="adv"
:divided="adv.divided"
:icon="adv.icon"
:key="index"
:title="adv.label">
</sc-contextmenu-item>
<sc-contextmenu-item command="refresh" divided icon="el-icon-refresh" suffix="Ctrl+R" title="重新加载"></sc-contextmenu-item>
</sc-contextmenu>
</template>
<script>
import config from '@/config/table'
import columnSetting from './columnSetting'
import scContextmenuItem from '@/components/scContextmenu/item.vue'
import scContextmenu from '@/components/scContextmenu/index.vue'
import { h } from 'vue'
export default {
name: 'scTable',
components: {
scContextmenu,
scContextmenuItem,
columnSetting,
},
props: {
vue: { type: Object },
contextMenus: { type: Array },
contextOpers: { type: Array, default: ['view', 'edit', 'del'] },
contextAdvs: { type: Array, default: [] },
tableName: { type: String, default: '' },
beforePost: {
type: Function,
@ -184,6 +231,10 @@ export default {
},
data() {
return {
current: {
row: null,
column: null,
},
scPageSize: this.pageSize,
isActivate: true,
emptyText: '暂无数据',
@ -231,6 +282,71 @@ export default {
this.isActivate = false
},
methods: {
async contextMenuCommand(command) {
if (typeof command === 'object') {
return command.action()
}
if (command === 'refresh') {
this.vue.reload()
return
}
if (command === 'view') {
this.vue.dialog.save = true
await this.$nextTick()
await this.vue.$refs.saveDialog.open('view', { id: this.current.row.id })
return
}
if (command === 'edit') {
this.vue.dialog.save = true
await this.$nextTick()
await this.vue.$refs.saveDialog.open('edit', { id: this.current.row.id })
return
}
if (command === 'del') {
try {
await this.$confirm(h('div', [h('p', '是否确认删除?'), h('p', this.current.row.id)]), '提示', {
type: 'warning',
})
} catch {
return
}
await this.vue.deleteRow(this.current.row)
return
}
const kv = command.split('^|^')
let value
try {
value = await this.$prompt(`仅显示 ${kv[0]} ${kv[1]}`, '高级筛选', {
inputPlaceholder: '一行一个',
inputPattern: /.+/,
inputType: 'textarea',
inputValue: command.split('^|^')[2],
})
} catch {
return
}
value = value.value?.split('\n') ?? ['']
this.vue.query.dynamicFilter.filters.push({
field: kv[0],
operator: kv[1],
value: value.length === 1 ? value[0] : value,
})
this.upData()
},
contextMenuVisibleChange(visible) {
if (!visible) {
this.setCurrentRow()
}
},
rowContextmenu(row, column, event) {
if (!this.contextMenus) return
this.current.row = row
this.current.column = column
this.setCurrentRow(row)
this.$refs.contextmenu.openMenu(event)
},
//获取列
async getCustomColumn() {
this.userColumn = await config.columnSettingGet(this.tableName, this.column)

File diff suppressed because one or more lines are too long

View File

@ -5,7 +5,7 @@ import tool from '@/utils/tool'
export default {
successCode: 'succeed', //请求完成代码
pageSize: 20, //表格每一页条数
pageSizes: [10, 20, 30, 40, 50], //表格可设置的一页条数
pageSizes: [10, 20, 30, 40, 50, 60, 70, 80, 90, 100], //表格可设置的一页条数
paginationLayout: 'total, sizes, prev, pager, next, jumper', //表格分页布局,可设置"total, sizes, prev, pager, next, jumper"
parseData: function (res) {
//数据分析

View File

@ -16,6 +16,13 @@ import time from '@/directives/time'
import 'vue3-json-viewer/dist/index.css'
import JsonViewer from 'vue3-json-viewer'
// VAceEditor
import ace from 'ace-builds'
import 'ace-builds/src-noconflict/mode-json' // Load the language definition file used below
import 'ace-builds/src-noconflict/theme-github' // Load the theme definition file used below
import 'ace-builds/src-noconflict/theme-github_dark' // Load the theme definition file used below
import { VAceEditor } from 'vue3-ace-editor'
// sc组件
import scCron from '@/components/scCron/index.vue'
import scDialog from '@/components/scDialog'
@ -43,6 +50,7 @@ import naColIndicator from '@/components/naColIndicator/index.vue'
import naColOperation from '@/components/naColOperation'
import naColTags from '@/components/naColTags/index.vue'
import naColTime from '@/components/naColTime/index.vue'
import naColUser from '@/components/naColUser/index.vue'
import naDept from '@/components/naDept/index.vue'
import naDicCatalog from '@/components/naDicCatalog/index.vue'
import naFormEmail from '@/components/naFormEmail/index.vue'
@ -70,6 +78,8 @@ export default {
app.use(JsonViewer)
app.component('VAceEditor', VAceEditor)
// net-admin组件
app.component('naArea', naArea)
app.component('naButtonAdd', naButtonAdd)
@ -79,6 +89,7 @@ export default {
app.component('naColOperation', naColOperation)
app.component('naColTags', naColTags)
app.component('naColTime', naColTime)
app.component('naColUser', naColUser)
app.component('naDept', naDept)
app.component('naDicCatalog', naDicCatalog)
app.component('naFormEmail', naFormEmail)

View File

@ -484,6 +484,9 @@ textarea {
.mt-4 {
margin-top: 1rem;
}
.mt-8 {
margin-top: 2rem;
}
.w100p {
width: 100%;
@ -507,4 +510,11 @@ textarea {
.justify-content-center {
justify-content: center;
}
.indicator {
display: flex;
align-items: center;
justify-content: center;
gap: 0.5rem;
}

View File

@ -18,7 +18,16 @@
stripe>
<el-table-column :label="$t('接口路径')" prop="id"></el-table-column>
<el-table-column :label="$t('接口名称')" prop="name"></el-table-column>
<el-table-column :label="$t('请求方式')" prop="method"></el-table-column>
<na-col-indicator
:label="$t('请求方式')"
:options="
Object.entries(this.$GLOBAL.enums.httpMethods).map((x) => {
return { value: x[0].toUpperCase(), text: x[1][1] }
})
"
prop="method"
width="100">
</na-col-indicator>
<el-table-column :label="$t('接口描述')" prop="summary"></el-table-column>
</sc-table>
</el-main>

View File

@ -1,7 +1,7 @@
<template>
<el-container>
<el-main>
<el-card :header="$t('缓存统计')" shadow="never">
<el-header style="flex-direction: column; height: auto">
<div v-loading="statistics.version === ''" class="w100p">
<el-row :gutter="15">
<el-col :lg="4">
<el-card shadow="never">
@ -50,30 +50,16 @@
</el-card>
</el-col>
</el-row>
</el-card>
</div>
</el-header>
<el-card :header="$t('缓存管理')" shadow="never">
<el-container>
<el-aside>
<el-menu :default-active="query.filter.dbIndex" class="el-menu-vertical-demo">
<el-menu-item v-for="(i, index) in 16" :index="index" :key="index" @click="this.query.filter.dbIndex = index">
<el-icon>
<el-icon-notebook></el-icon-notebook>
</el-icon>
<span slot="title">DB{{ index }}</span>
</el-menu-item>
</el-menu>
</el-aside>
<el-main>
<sc-table :apiObj="$API.sys_cache.getAllEntries" :params="query" @row-click="rowClick" ref="table" row-key="key" stripe>
<el-table-column :label="$t('键名')" :min-width="300" prop="key" show-overflow-tooltip />
<el-table-column :label="$t('键值')" prop="data" show-overflow-tooltip />
<el-table-column :label="$t('滑动过期')" align="right" prop="sldExp" />
<el-table-column :label="$t('绝对过期')" align="right" prop="absExp" />
</sc-table>
</el-main>
</el-container>
</el-card>
<el-main class="nopadding">
<sc-table :apiObj="$API.sys_cache.getAllEntries" :params="query" @row-click="rowClick" ref="table" row-key="key" stripe>
<el-table-column :label="$t('键名')" prop="key" show-overflow-tooltip />
<el-table-column :label="$t('键值')" prop="data" show-overflow-tooltip />
<el-table-column :label="$t('滑动过期')" align="right" prop="sldExpTime" width="200" />
<el-table-column :label="$t('绝对过期')" align="right" prop="absExpTime" width="200" />
</sc-table>
</el-main>
</el-container>
<na-info v-if="dialog.info" ref="info"></na-info>
@ -93,7 +79,7 @@ export default {
return {
query: {
filter: {
dbIndex: 0,
dbIndex: 1,
},
},
dialog: {
@ -145,4 +131,7 @@ export default {
flex-direction: column;
gap: 1rem;
}
.el-card {
overflow: unset;
}
</style>

View File

@ -2,14 +2,34 @@
<el-container>
<el-header>
<div class="left-panel">
<na-search
:controls="[
{
type: 'select',
field: ['dy', 'enabled'],
options: [
{ label: '启用', value: true },
{ label: '禁用', value: false },
],
placeholder: '是否启用',
style: 'width:10rem',
},
]"
:vue="this"
@search="onSearch"
ref="search" />
</div>
<div class="right-panel">
<na-button-add :vue="this"></na-button-add>
<el-button :disabled="selection.length === 0" @click="batchDel" icon="el-icon-delete" plain type="danger"></el-button>
</div>
<div class="right-panel"></div>
</el-header>
<el-main class="nopadding">
<sc-table
:apiObj="$API.sys_config.pagedQuery"
:context-menus="['id', 'userRegisterConfirm', 'enabled', 'createdTime']"
:params="query"
:vue="this"
@selection-change="
(items) => {
selection = items
@ -18,23 +38,24 @@
ref="table"
row-key="id"
stripe>
<el-table-column type="selection"></el-table-column>
<el-table-column :label="$t('配置编号')" prop="id"></el-table-column>
<el-table-column :label="$t('用户注册')">
<el-table-column :label="$t('默认部门')" prop="userRegisterDept.name"></el-table-column>
<el-table-column :label="$t('默认角色')" prop="userRegisterRole.name"></el-table-column>
<el-table-column :label="$t('人工审核')" prop="userRegisterConfirm">
<el-table-column align="center" type="selection"></el-table-column>
<el-table-column :label="$t('配置编号')" align="center" prop="id"></el-table-column>
<el-table-column :label="$t('用户注册')" align="center">
<el-table-column :label="$t('默认部门')" align="center" prop="userRegisterDept.name"></el-table-column>
<el-table-column :label="$t('默认角色')" align="center" prop="userRegisterRole.name"></el-table-column>
<el-table-column :label="$t('人工审核')" align="center" prop="userRegisterConfirm">
<template #default="scope">
<el-switch v-model="scope.row.userRegisterConfirm" @change="changeSwitch($event, scope.row)"></el-switch>
</template>
</el-table-column>
</el-table-column>
<el-table-column :label="$t('启用')" prop="enabled">
<el-table-column :label="$t('启用')" align="center" prop="enabled">
<template #default="scope">
<el-switch v-model="scope.row.enabled" @change="changeSwitch($event, scope.row)"></el-switch>
</template>
</el-table-column>
<el-table-column :label="$t('创建时间')" align="center" prop="createdTime"></el-table-column>
<na-col-operation
:buttons="
naColOperation.buttons.concat({
@ -42,6 +63,7 @@
confirm: true,
title: '删除部门',
click: rowDel,
type: 'danger',
})
"
:vue="this" />
@ -60,8 +82,10 @@
import saveDialog from './save'
import naColOperation from '@/config/naColOperation'
import table from '@/config/table'
import tool from '@/utils/tool'
export default {
inject: ['reload'],
computed: {
table() {
return table
@ -80,17 +104,42 @@ export default {
info: false,
},
selection: [],
search: {
query: {
dynamicFilter: {
field: 'id',
operator: 'contains',
value: '',
filters: [],
},
filter: {},
},
}
},
mounted() {},
methods: {
//搜索
onSearch(form) {
if (Array.isArray(form.dy.createdTime)) {
const start = new Date(form.dy.createdTime[0])
const end = new Date(form.dy.createdTime[1])
this.query.dynamicFilter.filters.push({
field: 'createdTime',
operator: 'dateRange',
value: [
tool.dateFormat(start.setDate(start.getDate() + 1)).substring(0, 10),
tool.dateFormat(end.setDate(end.getDate() + 1)).substring(0, 10),
],
})
}
if (typeof form.dy.enabled === 'boolean') {
this.query.dynamicFilter.filters.push({
field: 'enabled',
operator: 'eq',
value: form.dy.enabled,
})
}
this.$refs.table.upData()
},
//表格内开关事件
async changeSwitch(event, row) {
try {

View File

@ -32,8 +32,10 @@
<el-main class="nopadding">
<sc-table
:apiObj="$API.sys_dept.query"
:context-menus="['id', 'name', 'sort', 'enabled', 'createdTime', 'summary']"
:default-sort="{ prop: 'sort', order: 'descending' }"
:params="query"
:vue="this"
@selection-change="
(items) => {
selection = items
@ -49,7 +51,7 @@
<el-table-column type="selection" width="50"></el-table-column>
<el-table-column :label="$t('部门编号')" prop="id" sortable="custom"></el-table-column>
<el-table-column :label="$t('部门名称')" prop="name" sortable="custom"></el-table-column>
<el-table-column :label="$t('排序')" prop="sort" sortable="custom"></el-table-column>
<el-table-column :label="$t('排序')" align="right" prop="sort" sortable="custom"></el-table-column>
<na-col-indicator
:label="$t('状态')"
:options="[
@ -57,7 +59,7 @@
{ text: '禁用', type: 'danger', value: false, pulse: true },
]"
prop="enabled"></na-col-indicator>
<el-table-column :label="$t('创建时间')" prop="createdTime" sortable="custom"></el-table-column>
<el-table-column :label="$t('创建时间')" align="right" prop="createdTime" sortable="custom"></el-table-column>
<el-table-column :label="$t('备注')" prop="summary"></el-table-column>
<na-col-operation
:buttons="
@ -66,6 +68,7 @@
confirm: true,
title: '删除部门',
click: rowDel,
type: 'danger',
})
"
:vue="this" />
@ -97,6 +100,7 @@ export default {
components: {
saveDialog,
},
inject: ['reload'],
data() {
return {
query: {

View File

@ -24,8 +24,10 @@
<sc-table
:apiObj="$API.sys_dic.pagedQueryContent"
:before-post="(data) => data.dynamicFilter.filters.length > 0"
:context-menus="['key', 'value', 'createdTime']"
:default-sort="{ prop: 'createdTime', order: 'descending' }"
:params="query"
:vue="this"
@selection-change="
(items) => {
selection = items
@ -38,7 +40,7 @@
<el-table-column type="selection" width="50"></el-table-column>
<el-table-column :label="$t('项名')" prop="key" sortable="custom"></el-table-column>
<el-table-column :label="$t('项值')" prop="value" sortable="custom"></el-table-column>
<el-table-column :label="$t('创建时间')" prop="createdTime" sortable="custom"></el-table-column>
<el-table-column :label="$t('创建时间')" align="right" prop="createdTime" sortable="custom"></el-table-column>
<na-col-operation
:buttons="
naColOperation.buttons.concat({
@ -46,6 +48,7 @@
confirm: true,
title: '删除字典项',
click: rowDel,
type: 'danger',
})
"
:vue="this"></na-col-operation>
@ -74,6 +77,7 @@ export default {
},
components: { saveDialog },
props: { catalogId: Number },
inject: ['reload'],
data() {
return {
dialog: {

View File

@ -40,7 +40,8 @@
},
]"
:vue="this"
@search="onSearch" />
@search="onSearch"
ref="search" />
</div>
<div class="right-panel">
<na-button-add :vue="this" />
@ -51,8 +52,22 @@
<sc-table
v-loading="loading"
:apiObj="$API.sys_job.pagedQuery"
:context-menus="[
'id',
'jobName',
'executionCron',
'status',
'httpMethod',
'lastExecTime',
'lastStatusCode',
'nextExecTime',
'enabled',
'createdTime',
]"
:default-sort="{ prop: 'lastExecTime', order: 'descending' }"
:page-size="100"
:params="query"
:vue="this"
@selection-change="
(items) => {
selection = items
@ -64,8 +79,9 @@
row-key="id"
stripe>
<el-table-column type="selection"></el-table-column>
<el-table-column :label="$t('作业编号')" prop="id" width="150" />
<el-table-column :label="$t('作业名称')" prop="jobName" />
<el-table-column :label="$t('作业编号')" prop="id" sortable="custom" width="150" />
<el-table-column :label="$t('作业名称')" prop="jobName" show-overflow-tooltip sortable="custom" />
<el-table-column :label="$t('执行计划')" align="center" prop="executionCron" sortable="custom" width="150" />
<na-col-indicator
:label="$t('作业状态')"
:options="[
@ -83,20 +99,38 @@
"
prop="httpMethod"
width="100" />
<el-table-column :label="$t('上次执行时间')" prop="lastExecTime" sortable="custom" width="170" />
<el-table-column :label="$t('上次执行状态')" prop="lastStatusCode" sortable="custom" width="150" />
<el-table-column :label="$t('下次执行时间')" prop="nextExecTime" sortable="custom" width="170" />
<el-table-column :label="$t('启用')" prop="enabled" sortable="custom" width="100">
<el-table-column :label="$t('上次执行时间')" align="right" prop="lastExecTime" sortable="custom" width="120">
<template #default="scope">
<span v-if="scope.row.lastExecTime" v-time.tip="scope.row.lastExecTime"></span>
</template>
</el-table-column>
<na-col-indicator
:label="$t('上次执行状态')"
:options="
Object.entries(this.$GLOBAL.enums.httpStatusCodes).map((x) => {
return { value: x[0], text: x[1][1], type: x[0] === 'ok' ? 'success' : null }
})
"
prop="lastStatusCode"
width="120" />
<el-table-column :label="$t('下次执行时间')" align="right" prop="nextExecTime" sortable="custom" width="170" />
<el-table-column :label="$t('启用')" align="center" prop="enabled" sortable="custom" width="80">
<template #default="scope">
<el-switch v-model="scope.row.enabled" @change="changeSwitch($event, scope.row)"></el-switch>
</template>
</el-table-column>
<el-table-column :label="$t('创建时间')" prop="createdTime" sortable="custom" width="170" />
<el-table-column :label="$t('创建时间')" align="right" prop="createdTime" sortable="custom" width="100">
<template #default="scope">
<span v-if="scope.row.createdTime" v-time.tip="scope.row.createdTime"></span>
</template>
</el-table-column>
<na-col-operation
:buttons="
naColOperation.buttons.concat({
icon: 'el-icon-delete',
confirm: true,
type: 'danger',
title: $t('删除作业'),
click: rowDel,
})
@ -122,12 +156,19 @@ export default {
components: {
saveDialog,
},
inject: ['reload'],
data() {
return {
loading: false,
query: {
dynamicFilter: {
filters: [],
filters: [
{
field: 'enabled',
operator: 'eq',
value: true,
},
],
},
filter: {},
},
@ -146,7 +187,9 @@ export default {
return table
},
},
mounted() {},
mounted() {
this.$refs.search.form.dy.enabled = true
},
created() {},
methods: {
//表格内开关事件

View File

@ -34,10 +34,18 @@
<el-input v-model="form.nextTimeId" clearable />
</el-form-item>
<el-form-item :label="$t('请求头')" prop="requestHeader">
<el-input v-model="form.requestHeader" clearable rows="5" type="textarea" />
<v-ace-editor
v-model:value="form.requestHeader"
:theme="this.$TOOL.data.get('APP_DARK') ? 'github_dark' : 'github'"
lang="json"
style="height: 5rem; width: 100%" />
</el-form-item>
<el-form-item :label="$t('请求体')" prop="requestBody">
<el-input v-model="form.requestBody" clearable rows="5" type="textarea" />
<v-ace-editor
v-model:value="form.requestBody"
:theme="this.$TOOL.data.get('APP_DARK') ? 'github_dark' : 'github'"
lang="json"
style="height: 10rem; width: 100%" />
</el-form-item>
<el-form-item :label="$t('请求的网络地址')" prop="requestUrl">
<el-input v-model="form.requestUrl" clearable />

View File

@ -25,7 +25,7 @@
{
type: 'input',
field: ['dy', 'createdClientIp'],
placeholder: 'IP地址',
placeholder: '客户端IP',
style: 'width:15rem',
},
]"
@ -38,31 +38,33 @@
<el-main class="nopadding">
<sc-table
:apiObj="$API.sys_log.pagedQuery"
:context-menus="['id', 'httpStatusCode', 'extraData', 'createdClientIp', 'os', 'createdUserAgent', 'createdTime']"
:context-opers="['view']"
:default-sort="{ prop: 'createdTime', order: 'descending' }"
:params="query"
:vue="this"
@row-click="rowClick"
ref="table"
remoteFilter
remoteSort
row-key="id"
stripe>
<el-table-column :label="$t('日志编号')" prop="id" sortable="custom"></el-table-column>
<el-table-column :label="$t('日志时间')" prop="createdTime" sortable="custom"></el-table-column>
<el-table-column :label="$t('结果')" prop="httpStatusCode" sortable="custom">
<el-table-column :label="$t('日志编号')" prop="id" sortable="custom" width="150"></el-table-column>
<el-table-column :label="$t('结果')" align="center" prop="httpStatusCode" sortable="custom" width="80">
<template #default="scope">
<sc-status-indicator :type="scope.row.httpStatusCode === 200 ? 'success' : 'danger'" />
{{ scope.row.httpStatusCode === 200 ? '成功' : '失败' }}
</template>
</el-table-column>
<el-table-column :label="$t('登录名')" prop="extraData" sortable="custom"></el-table-column>
<el-table-column :label="$t('IP地址')" prop="createdClientIp" sortable="custom"></el-table-column>
<el-table-column :label="$t('操作系统')" prop="os" sortable="custom"></el-table-column>
<el-table-column
:label="$t('用户代理')"
min-width="200"
prop="createdUserAgent"
show-overflow-tooltip
sortable="custom"></el-table-column>
<el-table-column :label="$t('登录名')" prop="extraData" sortable="custom" width="200"></el-table-column>
<el-table-column :label="$t('客户端IP')" prop="createdClientIp" sortable="custom" width="200">
<template #default="scope">
<na-ip :ip="scope.row.createdClientIp"></na-ip>
</template>
</el-table-column>
<el-table-column :label="$t('操作系统')" prop="os" width="150"></el-table-column>
<el-table-column :label="$t('用户代理')" prop="createdUserAgent" show-overflow-tooltip sortable="custom"></el-table-column>
<el-table-column :label="$t('创建时间')" align="right" prop="createdTime" sortable="custom" width="170"></el-table-column>
</sc-table>
</el-main>
</el-container>
@ -83,6 +85,7 @@ export default {
naInfo,
},
watch: {},
inject: ['reload'],
data() {
return {
query: {

View File

@ -10,7 +10,7 @@
type: 'input',
field: ['filter', 'id'],
placeholder: '日志编号',
style: 'width:15rem',
style: 'width:12rem',
},
{
multiple: true,
@ -24,7 +24,7 @@
{ label: '90x', value: '900,999' },
],
placeholder: '状态码',
style: 'width:20rem',
style: 'width:15rem',
},
{
type: 'cascader',
@ -37,14 +37,14 @@
{
type: 'input',
field: ['dy', 'createdUserName'],
placeholder: '用户',
style: 'width:15rem',
placeholder: '用户',
style: 'width:12rem',
},
{
type: 'input',
field: ['dy', 'createdClientIp'],
placeholder: '客户端IP',
style: 'width:15rem',
style: 'width:12rem',
},
]"
:vue="this"
@ -55,8 +55,21 @@
<el-main class="nopadding">
<sc-table
:apiObj="$API.sys_log.pagedQuery"
:context-menus="[
'id',
'httpStatusCode',
'apiId',
'createdUserName',
'method',
'duration',
'createdClientIp',
'os',
'createdTime',
]"
:context-opers="[]"
:default-sort="{ prop: 'createdTime', order: 'descending' }"
:params="query"
:vue="this"
@row-click="rowClick"
ref="table"
remoteFilter
@ -64,33 +77,52 @@
row-key="id"
stripe>
<el-table-column :label="$t('日志编号')" align="center" prop="id" sortable="custom" width="150"></el-table-column>
<el-table-column :label="$t('日志时间')" align="center" prop="createdTime" sortable="custom" width="170"></el-table-column>
<el-table-column :label="$t('响应码')" align="center" prop="httpStatusCode" sortable="custom" width="90"></el-table-column>
<el-table-column :label="$t('请求服务')">
<el-table-column :label="$t('响应码')" align="center" prop="httpStatusCode" sortable="custom" width="100">
<template #default="scope">
<div class="indicator">
<sc-status-indicator
:style="`background: #${Math.abs(this.$TOOL.crypto.hashCode(scope.row.httpStatusCode)).toString(16).substring(0, 6)}`" />
<span> {{ scope.row.httpStatusCode }}</span>
</div>
</template>
</el-table-column>
<el-table-column :label="$t('请求服务')" align="center">
<el-table-column :label="$t('路径')" prop="apiId" show-overflow-tooltip sortable="custom">
<template #default="scope">
<p>{{ scope.row.apiId }}</p>
<p>{{ scope.row.apiSummary }}</p>
</template>
</el-table-column>
<el-table-column :label="$t('方法')" align="center" prop="method" sortable="custom" width="100">
<template #default="scope">
<div class="indicator">
<sc-status-indicator
:style="`background: #${Math.abs(this.$TOOL.crypto.hashCode(scope.row.method)).toString(16).substring(0, 6)}`" />
<span> {{ scope.row.method }}</span>
</div>
</template>
</el-table-column>
<el-table-column
:label="$t('路径')"
min-width="150"
prop="apiId"
show-overflow-tooltip
sortable="custom"></el-table-column>
<el-table-column :label="$t('描述')" prop="apiSummary"></el-table-column>
<el-table-column :label="$t('方法')" align="center" prop="method" sortable="custom" width="100"></el-table-column>
<el-table-column
:formatter="(row) => tool.groupSeparator((row.duration / 1000).toFixed(0))"
:label="$t('耗时(毫秒)')"
:formatter="(row) => `${tool.groupSeparator((row.duration / 1000).toFixed(0))} ms`"
:label="$t('耗时')"
align="right"
prop="duration"
sortable="custom"
width="120">
</el-table-column>
</el-table-column>
<el-table-column :label="$t('用户')" prop="createdUserName" sortable="custom">
<el-table-column :label="$t('用户')" prop="createdUserName" sortable="custom" width="150">
<template #default="scope">
{{ scope.row.apiId === 'api/sys/user/pwd.login' ? scope.row.extraData : scope.row.createdUserName }}
</template>
</el-table-column>
<el-table-column :label="$t('客户端IP')" prop="createdClientIp" sortable="custom" width="150"></el-table-column>
<el-table-column :label="$t('操作系统')" align="center" prop="os" sortable="custom"></el-table-column>
<el-table-column :label="$t('客户端IP')" prop="createdClientIp" show-overflow-tooltip sortable="custom" width="200">
<template #default="scope">
<na-ip :ip="scope.row.createdClientIp"></na-ip>
</template>
</el-table-column>
<el-table-column :label="$t('操作系统')" align="center" prop="os" width="150"></el-table-column>
<el-table-column :label="$t('创建时间')" align="right" prop="createdTime" sortable="custom" width="170"></el-table-column>
</sc-table>
</el-main>
</el-container>
@ -106,6 +138,7 @@ import tool from '@/utils/tool'
import ScTable from '@/components/scTable/index.vue'
export default {
inject: ['reload'],
computed: {
tool() {
return tool

View File

@ -63,7 +63,7 @@
<el-form-item :label="$t('是否隐藏')" prop="meta.hidden">
<el-checkbox v-model="form.meta.hidden">隐藏菜单</el-checkbox>
<el-checkbox v-model="form.meta.hiddenBreadCrumb">隐藏面包屑</el-checkbox>
<div class="el-form-item-msg">菜单不显示在导航中但用户依然可以访问例如详情页</div>
<div class="el-form-item-msg" style="margin-left: 1rem">菜单不显示在导航中但用户依然可以访问例如详情页</div>
</el-form-item>
<el-form-item :label="$t('整页路由')" prop="fullPage">
<el-switch v-model="form.meta.fullPage" />
@ -149,7 +149,7 @@ export default {
},
//表单注入数据
setData(data, pid) {
Object.assign(this.form, data, { parentId: pid })
this.form = Object.assign({}, data, { parentId: pid })
},
},
}

View File

@ -32,8 +32,10 @@
<sc-table
v-loading="loading"
:apiObj="$API.sys_sitemsg.pagedQuery"
:context-menus="['id', 'createdUserName', 'msgType', 'title', 'summary', 'createdTime']"
:default-sort="{ prop: 'createdTime', order: 'descending' }"
:params="query"
:vue="this"
@selection-change="
(items) => {
selection = items
@ -45,8 +47,8 @@
row-key="id"
stripe>
<el-table-column type="selection"></el-table-column>
<el-table-column :label="$t('消息编号')" prop="id" width="150" />
<na-col-avatar :label="$t('用户名')" prop="creator.userName" />
<el-table-column :label="$t('消息编号')" prop="id" sortable="custom" width="150" />
<na-col-avatar :label="$t('用户名')" prop="createdUserName" />
<na-col-indicator
:label="$t('消息类型')"
:options="[
@ -56,9 +58,9 @@
prop="msgType"
width="100"></na-col-indicator>
<el-table-column :label="$t('消息主题')" min-width="150" prop="title" show-overflow-tooltip />
<el-table-column :label="$t('消息摘要')" min-width="200" prop="summary" show-overflow-tooltip />
<el-table-column :label="$t('创建时间')" prop="createdTime" />
<el-table-column :label="$t('消息主题')" prop="title" show-overflow-tooltip sortable="custom" />
<el-table-column :label="$t('消息摘要')" prop="summary" show-overflow-tooltip sortable="custom" />
<el-table-column :label="$t('创建时间')" align="right" prop="createdTime" sortable="custom" width="170" />
<na-col-operation
:buttons="
naColOperation.buttons.concat({
@ -66,6 +68,7 @@
confirm: true,
title: $t('删除消息'),
click: rowDel,
type: 'danger',
})
"
:vue="this" />
@ -89,6 +92,7 @@ export default {
components: {
saveDialog,
},
inject: ['reload'],
data() {
return {
loading: false,

View File

@ -52,8 +52,10 @@
<el-main class="nopadding">
<sc-table
:apiObj="$API.sys_role.pagedQuery"
:context-menus="['id', 'name', 'sort', 'enabled', 'ignorePermissionControl', 'dataScope', 'displayDashboard', 'createdTime']"
:default-sort="{ prop: 'sort', order: 'descending' }"
:params="query"
:vue="this"
@selection-change="
(items) => {
selection = items
@ -67,7 +69,7 @@
<el-table-column type="selection" width="50"></el-table-column>
<el-table-column :label="$t('角色编号')" prop="id" sortable="custom"></el-table-column>
<el-table-column :label="$t('角色名称')" prop="name" sortable="custom"></el-table-column>
<el-table-column :label="$t('排序')" prop="sort" sortable="custom"></el-table-column>
<el-table-column :label="$t('排序')" align="right" prop="sort" sortable="custom"></el-table-column>
<na-col-indicator
:label="$t('状态')"
:options="[
@ -82,12 +84,17 @@
{ text: '否', type: 'danger', value: false },
]"
prop="ignorePermissionControl"></na-col-indicator>
<el-table-column :label="$t('数据范围')" prop="dataScope" sortable="custom">
<template #default="scope">
{{ this.$GLOBAL.enums.dataScopes[scope.row.dataScope][1] }}
</template>
</el-table-column>
<na-col-indicator
:label="$t('数据范围')"
:options="
Object.entries(this.$GLOBAL.enums.dataScopes).map((x) => {
return { value: x[0], text: x[1][1] }
})
"
prop="dataScope"
sortable="custom"
width="100">
</na-col-indicator>
<na-col-indicator
:label="$t('显示仪表板')"
@ -97,7 +104,7 @@
]"
prop="displayDashboard"></na-col-indicator>
<el-table-column :label="$t('创建时间')" prop="createdTime" sortable="custom"></el-table-column>
<el-table-column :label="$t('创建时间')" align="right" prop="createdTime" sortable="custom"></el-table-column>
<na-col-operation
:buttons="
naColOperation.buttons.concat({
@ -105,6 +112,7 @@
confirm: true,
title: '删除角色',
click: rowDel,
type: 'danger',
})
"
:vue="this"></na-col-operation>
@ -136,6 +144,7 @@ export default {
components: {
saveDialog,
},
inject: ['reload'],
data() {
return {
query: {

View File

@ -48,8 +48,11 @@
<sc-table
v-loading="loading"
:apiObj="$API.sys_user.pagedQuery"
:context-menus="['id', 'userName', 'mobile', 'email', 'enabled', 'createdTime']"
:context-opers="['view', 'edit']"
:default-sort="{ prop: 'createdTime', order: 'descending' }"
:params="query"
:vue="this"
@selection-change="
(items) => {
selection = items
@ -63,16 +66,16 @@
<el-table-column type="selection"></el-table-column>
<el-table-column :label="$t('用户编号')" prop="id" sortable="custom" width="150"></el-table-column>
<na-col-avatar :label="$t('用户名')" prop="userName" />
<el-table-column :label="$t('手机号')" prop="mobile" sortable="custom" width="120"></el-table-column>
<el-table-column :label="$t('手机号')" align="center" prop="mobile" sortable="custom" width="120"></el-table-column>
<el-table-column :label="$t('邮箱')" prop="email" sortable="custom"></el-table-column>
<na-col-tags :label="$t('所属角色')" @click="(item) => openDialog('sys_role', item.id, 'roleSave')" field="name" prop="roles" />
<na-col-tags :label="$t('所属部门')" @click="(item) => openDialog('sys_dept', item.id, 'deptSave')" field="name" prop="dept" />
<el-table-column :label="$t('启用')" prop="enabled" sortable="custom" width="100">
<el-table-column :label="$t('启用')" align="center" prop="enabled" sortable="custom" width="80">
<template #default="scope">
<el-switch v-model="scope.row.enabled" @change="changeSwitch($event, scope.row)"></el-switch>
</template>
</el-table-column>
<el-table-column :label="$t('创建时间')" prop="createdTime" sortable="custom"></el-table-column>
<el-table-column :label="$t('创建时间')" align="right" prop="createdTime" sortable="custom"></el-table-column>
<na-col-operation :vue="this"></na-col-operation>
</sc-table>
</el-main>
@ -99,6 +102,7 @@ export default {
roleSaveDialog,
deptSaveDialog,
},
inject: ['reload'],
data() {
return {
loading: false,

View File

@ -13,6 +13,9 @@
<el-form-item prop="avatar">
<sc-upload v-model="form.avatar" :title="$t('上传头像')"></sc-upload>
</el-form-item>
<el-form-item v-if="mode === 'view'" :label="$t('唯一编码')" prop="id">
<el-input v-model="form.id" clearable></el-input>
</el-form-item>
<el-form-item :label="$t('登录账号')" prop="userName">
<el-input v-model="form.userName" :placeholder="$t('用于登录系统')" clearable></el-input>
</el-form-item>
@ -216,10 +219,10 @@
<el-tab-pane v-if="mode === 'view'" :label="$t('原始数据')">
<json-viewer
:expand-depth="5"
:expanded="true"
:theme="this.$TOOL.data.get('APP_DARK') ? 'dark' : 'light'"
:value="form"
copyable
expanded
sort></json-viewer>
</el-tab-pane>
</el-tabs>