fix: 🐛 样式问题

This commit is contained in:
tk 2024-12-20 18:47:38 +08:00 committed by nsnail
parent 4d45a72243
commit 377c28c570
14 changed files with 218 additions and 134 deletions

View File

@ -36,7 +36,7 @@
"prettier-plugin-organize-attributes": "1.0.0", "prettier-plugin-organize-attributes": "1.0.0",
"sass": "1.82.0", "sass": "1.82.0",
"terser": "5.37.0", "terser": "5.37.0",
"vite": "6.0.3" "vite": "5.1.8"
}, },
"browserslist": [ "browserslist": [
"> 1%", "> 1%",

View File

@ -39,7 +39,7 @@
</el-tabs> </el-tabs>
</div> </div>
<template #footer> <template #footer>
<el-button @click="clear" text>{{ $t('清除') }}</el-button> <el-button @click="clear">{{ $t('清除') }}</el-button>
<el-button @click="dialogVisible = false">{{ $t('取消') }}</el-button> <el-button @click="dialogVisible = false">{{ $t('取消') }}</el-button>
</template> </template>
</el-dialog> </el-dialog>

View File

@ -55,11 +55,11 @@
:page-size="scPageSize" :page-size="scPageSize"
:page-sizes="pageSizes" :page-sizes="pageSizes"
:pager-count="pagerCount" :pager-count="pagerCount"
:small="true"
:total="total" :total="total"
@current-change="paginationChange" @current-change="paginationChange"
@update:page-size="pageSizeChange" @update:page-size="pageSizeChange"
background></el-pagination> background
size="small"></el-pagination>
</div> </div>
<div v-if="!hideDo" class="scTable-do"> <div v-if="!hideDo" class="scTable-do">
<el-button <el-button
@ -105,9 +105,9 @@
<el-form label-position="left" label-width="10rem"> <el-form label-position="left" label-width="10rem">
<el-form-item :label="$t('表格尺寸')"> <el-form-item :label="$t('表格尺寸')">
<el-radio-group v-model="config.size" @change="configSizeChange" size="small"> <el-radio-group v-model="config.size" @change="configSizeChange" size="small">
<el-radio-button label="large">{{ $t('大') }}</el-radio-button> <el-radio-button value="large">{{ $t('大') }}</el-radio-button>
<el-radio-button label="default">{{ $t('正常') }}</el-radio-button> <el-radio-button value="default">{{ $t('正常') }}</el-radio-button>
<el-radio-button label="small">{{ $t('小') }}</el-radio-button> <el-radio-button value="small">{{ $t('小') }}</el-radio-button>
</el-radio-group> </el-radio-group>
</el-form-item> </el-form-item>
<el-form-item :label="$t('样式')"> <el-form-item :label="$t('样式')">
@ -232,6 +232,7 @@ export default {
fieldFilter, fieldFilter,
}, },
props: { props: {
dblClickDisable: { type: Boolean, default: false },
vue: { type: Object }, vue: { type: Object },
contextMenus: { type: Array }, contextMenus: { type: Array },
contextOpers: { type: Array, default: ['copy', 'add', 'view', 'edit', 'del'] }, contextOpers: { type: Array, default: ['copy', 'add', 'view', 'edit', 'del'] },
@ -309,7 +310,7 @@ export default {
}, },
data() { data() {
return { return {
pagerCount: 10, pagerCount: 11,
current: { current: {
row: null, row: null,
column: null, column: null,
@ -338,7 +339,7 @@ export default {
} }
}, },
mounted() { mounted() {
this.pagerCount = document.body.clientWidth < 1000 ? 3 : 10 this.pagerCount = document.body.clientWidth < 1000 ? 3 : 11
// //
if (this.column) { if (this.column) {
this.getCustomColumn() this.getCustomColumn()
@ -363,6 +364,9 @@ export default {
}, },
methods: { methods: {
dbClick(row) { dbClick(row) {
if (this.dblClickDisable) {
return
}
if (this.vue.dialog) { if (this.vue.dialog) {
this.vue.dialog.save = { mode: 'view', row: { id: row.id } } this.vue.dialog.save = { mode: 'view', row: { id: row.id } }
} }

View File

@ -48,7 +48,6 @@ export default {
data() { data() {
return { return {
cursor: { cursor: {
position: 0,
index: 0, index: 0,
}, },
input: '', input: '',
@ -59,7 +58,6 @@ export default {
}, },
watch: { watch: {
result() { result() {
this.cursor.position = 0
this.cursor.index = 0 this.cursor.index = 0
}, },
}, },
@ -86,12 +84,15 @@ export default {
return return
} }
if (e.keyCode === 40) { if (e.keyCode === 40) {
this.cursor.index = Math.abs(++this.cursor.position % this.result.length) this.cursor.index = ++this.cursor.index % this.result.length
e.preventDefault() e.preventDefault()
return return
} }
if (e.keyCode === 38) { if (e.keyCode === 38) {
this.cursor.index = Math.abs(--this.cursor.position % this.result.length) this.cursor.index = --this.cursor.index % this.result.length
if (this.cursor.index < 0) {
this.cursor.index += this.result.length
}
e.preventDefault() e.preventDefault()
return return
} }

View File

@ -1,13 +1,41 @@
<template> <template>
<el-container v-loading="loading"> <el-container v-loading="loading">
<el-header class="flex" style="justify-content: space-evenly; height: unset">
<div v-if="failJobs">
<el-badge :hidden="fail === 0" :value="`${$TOOL.time.getFormatTime(new Date(failJobViewTime).getTime())} 至今 ${fail}个`">
<el-button
@click="
() => {
this.$router.push({ path: '/sys/job', query: { view: 'fail' } })
this.$emit('closed')
}
"
plain
type="danger"
>{{ $t('异常日志') }}
</el-button>
</el-badge>
</div>
<el-button @click="refresh" circle icon="el-icon-refresh"></el-button>
<div>
<el-badge :hidden="jobsCnt === 0" :value="jobsCnt" type="primary">
<el-button
@click="
() => {
this.$router.push({ path: '/sys/job' })
this.$emit('closed')
}
"
>{{ $t('作业管理') }}
</el-button>
</el-badge>
</div>
</el-header>
<el-main> <el-main>
<el-empty v-if="jobs.length === 0" :image-size="120"> <el-empty v-if="jobs.length === 0" :image-size="120">
<template #description> <template #description>
<h2>{{ $t('没有正在执行的作业') }}</h2> <h2>{{ $t('没有正在执行的作业') }}</h2>
</template> </template>
<p style="color: var(--el-color-info); line-height: 1.5; margin: 0 3rem">
在处理耗时过久的作业时为了不阻碍正在处理的工作可在作业中心进行异步执行
</p>
</el-empty> </el-empty>
<el-row :gutter="10"> <el-row :gutter="10">
<el-col :lg="12"> <el-col :lg="12">
@ -18,7 +46,13 @@
<p>未发现新的异常作业</p> <p>未发现新的异常作业</p>
</template> </template>
</el-empty> </el-empty>
<el-card v-else v-for="job in failJobs" :class="`user-bar-jobs-item alert`" :key="job.job.id" shadow="hover"> <el-card
v-else
v-for="job in failJobs"
:class="`user-bar-jobs-item alert`"
:key="job.job.id"
@click="dialog.jobRecordSave = { mode: 'view', row: { id: job.id } }"
shadow="hover">
<div class="user-bar-jobs-item-body"> <div class="user-bar-jobs-item-body">
<div class="jobIcon"> <div class="jobIcon">
{{ job.httpStatusCode.toUpperCase().slice(0, 2) }} {{ job.httpStatusCode.toUpperCase().slice(0, 2) }}
@ -32,15 +66,8 @@
</p> </p>
</div> </div>
<div class="bottom"> <div class="bottom">
<div class="status failJobs"> <div class="status">
{{ job.responseBody }} <el-tag type="danger">{{ job.responseBody }}</el-tag>
</div>
<div class="handler">
<el-button
@click="dialog.jobRecordSave = { mode: 'view', row: { id: job.id } }"
circle
icon="el-icon-view"
type="danger"></el-button>
</div> </div>
</div> </div>
</div> </div>
@ -52,6 +79,7 @@
v-for="job in jobs" v-for="job in jobs"
:class="`user-bar-jobs-item ${job.lastStatusCode === 'oK' ? '' : 'alert'}`" :class="`user-bar-jobs-item ${job.lastStatusCode === 'oK' ? '' : 'alert'}`"
:key="job.id" :key="job.id"
@click="dialog.jobSave = { mode: 'view', row: { id: job.id }, tabId: 'record' }"
shadow="hover"> shadow="hover">
<div class="user-bar-jobs-item-body"> <div class="user-bar-jobs-item-body">
<div class="jobIcon"> <div class="jobIcon">
@ -72,13 +100,6 @@
>{{ $t('空闲') }} >{{ $t('空闲') }}
</el-tag> </el-tag>
</div> </div>
<div class="handler">
<el-button
:type="job.lastStatusCode === 'oK' ? 'primary' : 'danger'"
@click="dialog.jobSave = { mode: 'view', row: { id: job.id }, tabId: 'record' }"
circle
icon="el-icon-view"></el-button>
</div>
</div> </div>
</div> </div>
</div> </div>
@ -86,37 +107,6 @@
</el-col> </el-col>
</el-row> </el-row>
</el-main> </el-main>
<el-footer class="flex" style="justify-content: space-evenly; height: unset">
<div v-if="failJobs">
<el-badge :hidden="fail === 0" :value="`${$TOOL.time.getFormatTime(new Date(failJobViewTime).getTime())} 至今 ${fail}个`">
<el-button
@click="
() => {
this.$router.push({ path: '/sys/job', query: { view: 'fail' } })
this.$emit('closed')
}
"
plain
type="danger"
>{{ $t('异常日志') }}</el-button
>
</el-badge>
</div>
<el-button @click="refresh" circle icon="el-icon-refresh"></el-button>
<div>
<el-badge :hidden="jobsCnt === 0" :value="jobsCnt">
<el-button
@click="
() => {
this.$router.push({ path: '/sys/job' })
this.$emit('closed')
}
"
>{{ $t('作业管理') }}</el-button
>
</el-badge>
</div>
</el-footer>
</el-container> </el-container>
<jobSaveDialog <jobSaveDialog
@ -133,6 +123,7 @@
<script> <script>
import { defineAsyncComponent } from 'vue' import { defineAsyncComponent } from 'vue'
import scPageHeader from '@/components/scPageHeader'
const jobSaveDialog = defineAsyncComponent(() => import('@/views/sys/job/all/save.vue')) const jobSaveDialog = defineAsyncComponent(() => import('@/views/sys/job/all/save.vue'))
const jobRecordSaveDialog = defineAsyncComponent(() => import('@/views/sys/job/record/save.vue')) const jobRecordSaveDialog = defineAsyncComponent(() => import('@/views/sys/job/record/save.vue'))
@ -144,6 +135,7 @@ export default {
}, },
}, },
components: { components: {
scPageHeader,
jobSaveDialog, jobSaveDialog,
jobRecordSaveDialog, jobRecordSaveDialog,
}, },
@ -170,6 +162,7 @@ export default {
value: true, value: true,
operator: 'eq', operator: 'eq',
}, },
pageSize: 10,
}), }),
this.$API.sys_job.pagedQueryRecord.post({ this.$API.sys_job.pagedQueryRecord.post({
dynamicFilter: { dynamicFilter: {
@ -204,6 +197,7 @@ export default {
operator: 'greaterThan', operator: 'greaterThan',
value: this.failJobViewTime, value: this.failJobViewTime,
}, },
pageSize: 10,
}), }),
]) ])
@ -229,6 +223,7 @@ export default {
<style scoped> <style scoped>
.user-bar-jobs-item { .user-bar-jobs-item {
margin-bottom: 0.5rem; margin-bottom: 0.5rem;
cursor: pointer;
} }
.user-bar-jobs-item:hover { .user-bar-jobs-item:hover {
@ -241,48 +236,44 @@ export default {
.user-bar-jobs-item-body { .user-bar-jobs-item-body {
display: flex; display: flex;
gap: 1rem;
} }
.user-bar-jobs-item-body .jobIcon { .user-bar-jobs-item-body .jobIcon {
width: 3rem; width: 3rem;
height: 3rem; height: 3rem;
background: var(--el-color-primary-light-9); background: var(--el-color-primary-light-9);
margin-right: 2rem;
display: flex;
justify-content: center;
align-items: center;
color: var(--el-color-primary);
border-radius: 1.5rem; border-radius: 1.5rem;
text-align: center;
color: var(--el-color-primary);
line-height: 3rem;
} }
.user-bar-jobs-item-body .jobMain { .user-bar-jobs-item-body .jobMain {
flex: 1; flex: 1;
overflow: hidden;
} }
.user-bar-jobs-item-body .title h2 { .user-bar-jobs-item-body .title h2 {
font-size: 1rem; font-size: 1rem;
margin-bottom: 0.5rem;
} }
.user-bar-jobs-item-body .title p { .user-bar-jobs-item-body .title p {
font-size: 1rem; font-size: 1rem;
color: var(--el-color-info); color: var(--el-color-info);
margin-top: 0.5rem; line-height: 1.5rem;
} }
.user-bar-jobs-item-body .bottom { .user-bar-jobs-item-body .bottom {
display: flex; display: flex;
justify-content: space-between; justify-content: space-between;
align-items: center; align-items: center;
margin-top: 0.5rem;
} }
.user-bar-jobs-item.alert .jobIcon { .user-bar-jobs-item.alert .jobIcon {
background: var(--el-color-danger-light-9); background: var(--el-color-danger-light-9);
color: var(--el-color-danger); color: var(--el-color-danger);
} }
.status.failJobs {
color: var(--el-color-danger);
width: 18rem;
overflow: hidden;
}
</style> </style>

View File

@ -74,7 +74,7 @@
<search @success="searchVisible = false"></search> <search @success="searchVisible = false"></search>
</el-dialog> </el-dialog>
<el-drawer v-model="tasksVisible" :size="800" :title="$t('作业中心')" destroy-on-close> <el-drawer v-model="tasksVisible" :size="800" :title="$t('作业中心')" @close="taskClose" destroy-on-close>
<tasks :fail="failJobCnt" @closed="tasksVisible = false"></tasks> <tasks :fail="failJobCnt" @closed="tasksVisible = false"></tasks>
</el-drawer> </el-drawer>
</template> </template>
@ -100,49 +100,7 @@ export default {
this.user = this.$GLOBAL.user this.user = this.$GLOBAL.user
let res = await this.$API.sys_sitemsg.unreadCount.post() let res = await this.$API.sys_sitemsg.unreadCount.post()
this.unreadCnt = res.data this.unreadCnt = res.data
await this.getFailJobsCnt()
if (this.$GLOBAL.permissions.some((x) => x === '*/*/*' || x === 'sys/job/userbar')) {
res = await this.$API.sys_job.countRecord.post({
dynamicFilter: {
filters: [
{
field: 'createdTime',
operator: 'dateRange',
value: [
this.$TOOL.data.get('APP_SET_FAIL_JOB_VIEW_TIME') ?? this.$TOOL.dateFormat(new Date(), 'yyyy-MM-dd'),
this.$TOOL.dateFormat(new Date(), 'yyyy-MM-dd hh:mm:ss'),
],
},
{
logic: 'or',
filters: [
{
field: 'httpStatusCode',
operator: 'range',
value: '300,399',
},
{
field: 'httpStatusCode',
operator: 'range',
value: '400,499',
},
{
field: 'httpStatusCode',
operator: 'range',
value: '500,599',
},
{
field: 'httpStatusCode',
operator: 'range',
value: '900,999',
},
],
},
],
},
})
this.failJobCnt = res.data
}
}, },
data() { data() {
return { return {
@ -160,6 +118,55 @@ export default {
} }
}, },
methods: { methods: {
async getFailJobsCnt() {
if (this.$GLOBAL.permissions.some((x) => x === '*/*/*' || x === 'sys/job/userbar')) {
const res = await this.$API.sys_job.countRecord.post({
dynamicFilter: {
filters: [
{
field: 'createdTime',
operator: 'dateRange',
value: [
this.$TOOL.data.get('APP_SET_FAIL_JOB_VIEW_TIME') ?? this.$TOOL.dateFormat(new Date(), 'yyyy-MM-dd'),
this.$TOOL.dateFormat(new Date(), 'yyyy-MM-dd hh:mm:ss'),
],
},
{
logic: 'or',
filters: [
{
field: 'httpStatusCode',
operator: 'range',
value: '300,399',
},
{
field: 'httpStatusCode',
operator: 'range',
value: '400,499',
},
{
field: 'httpStatusCode',
operator: 'range',
value: '500,599',
},
{
field: 'httpStatusCode',
operator: 'range',
value: '900,999',
},
],
},
],
},
})
this.failJobCnt = res.data
}
},
taskClose() {
setTimeout(() => {
this.getFailJobsCnt()
}, 2000)
},
clearData(fullClear) { clearData(fullClear) {
const loading = this.$loading() const loading = this.$loading()
this.$TOOL.cookie.clear() this.$TOOL.cookie.clear()

View File

@ -8,12 +8,14 @@ import router from './router'
import store from './store' import store from './store'
import App from './App.vue' import App from './App.vue'
import preload from '@/utils/preload' import preload from '@/utils/preload'
import passiveEventListener from '@/utils/passiveEventListener'
const app = createApp(App) const app = createApp(App)
app.use(ElementPlus) app.use(ElementPlus)
app.use(store) app.use(store)
app.use(i18n) app.use(i18n)
app.use(global) app.use(global)
app.use(passiveEventListener)
preload.install(app).then(() => { preload.install(app).then(() => {
app.use(router) app.use(router)

View File

@ -332,4 +332,8 @@
.el-collapse-item__header { .el-collapse-item__header {
color: var(--el-text-color-regular); color: var(--el-text-color-regular);
}
.adminui-header .el-drawer__header {
margin-bottom: 0;
} }

View File

@ -0,0 +1,77 @@
export default {
install() {
const eventListenerOptionsSupported = () => {
let supported = false
try {
const opts = Object.defineProperty({}, 'passive', {
get() {
supported = true
},
})
window.addEventListener('test', null, opts)
window.removeEventListener('test', null, opts)
} catch (e) {}
return supported
}
const defaultOptions = {
passive: true,
capture: false,
}
const supportedPassiveTypes = [
'scroll',
'wheel',
'touchstart',
'touchmove',
'touchenter',
'touchend',
'touchleave',
'mouseout',
'mouseleave',
'mouseup',
'mousedown',
'mousemove',
'mouseenter',
'mousewheel',
'mouseover',
]
const getDefaultPassiveOption = (passive, eventName) => {
if (passive !== undefined) return passive
return supportedPassiveTypes.indexOf(eventName) === -1 ? false : defaultOptions.passive
}
const getWritableOptions = (options) => {
const passiveDescriptor = Object.getOwnPropertyDescriptor(options, 'passive')
return passiveDescriptor && passiveDescriptor.writable !== true && passiveDescriptor.set === undefined
? Object.assign({}, options)
: options
}
const overwriteAddEvent = (superMethod) => {
EventTarget.prototype.addEventListener = function (type, listener, options) {
const usesListenerOptions = typeof options === 'object' && options !== null
const useCapture = usesListenerOptions ? options.capture : options
options = usesListenerOptions ? getWritableOptions(options) : {}
options.passive = getDefaultPassiveOption(options.passive, type)
options.capture = useCapture === undefined ? defaultOptions.capture : useCapture
superMethod.call(this, type, listener, options)
}
EventTarget.prototype.addEventListener._original = superMethod
}
const supportsPassive = eventListenerOptionsSupported()
if (supportsPassive) {
const addEvent = EventTarget.prototype.addEventListener
overwriteAddEvent(addEvent)
}
},
}

View File

@ -44,9 +44,6 @@ export default {
show: true, show: true,
alignTo: 'labelLine', alignTo: 'labelLine',
formatter: '{b} {d}%', formatter: '{b} {d}%',
textStyle: {
textBorderColor: 'transparent',
},
}, },
radius: this.api[i++].radius, radius: this.api[i++].radius,
type: 'pie', type: 'pie',

View File

@ -45,7 +45,9 @@
:theme="this.$TOOL.data.get('APP_SET_DARK') || this.$CONFIG.APP_SET_DARK ? 'github_dark' : 'github'" :theme="this.$TOOL.data.get('APP_SET_DARK') || this.$CONFIG.APP_SET_DARK ? 'github_dark' : 'github'"
lang="json" lang="json"
style="height: 10rem; width: 100%" /> style="height: 10rem; width: 100%" />
<el-button @click="form.requestHeader = jsonFormat(form.requestHeader)" type="text">{{ $t('JSON 格式化') }}</el-button> <el-button @click="form.requestHeader = jsonFormat(form.requestHeader)" link type="primary"
>{{ $t('JSON 格式化') }}
</el-button>
</el-form-item> </el-form-item>
<el-form-item :label="$t('请求体')" prop="requestBody"> <el-form-item :label="$t('请求体')" prop="requestBody">
<VAceEditor <VAceEditor
@ -53,7 +55,7 @@
:theme="this.$TOOL.data.get('APP_SET_DARK') || this.$CONFIG.APP_SET_DARK ? 'github_dark' : 'github'" :theme="this.$TOOL.data.get('APP_SET_DARK') || this.$CONFIG.APP_SET_DARK ? 'github_dark' : 'github'"
lang="json" lang="json"
style="height: 15rem; width: 100%" /> style="height: 15rem; width: 100%" />
<el-button @click="form.requestBody = jsonFormat(form.requestBody)" type="text">{{ $t('JSON 格式化') }}</el-button> <el-button @click="form.requestBody = jsonFormat(form.requestBody)" link type="primary">{{ $t('JSON 格式化') }}</el-button>
</el-form-item> </el-form-item>
<el-form-item :label="$t('请求的网络地址')" prop="requestUrl"> <el-form-item :label="$t('请求的网络地址')" prop="requestUrl">
<el-input v-model="form.requestUrl" clearable /> <el-input v-model="form.requestUrl" clearable />

View File

@ -137,7 +137,7 @@
<el-table-column :label="$t('用户数量')" align="right" width="100"> <el-table-column :label="$t('用户数量')" align="right" width="100">
<template #default="{ row }"> <template #default="{ row }">
<el-link @click.native="dialog.save = { mode: 'view', row, tabId: 'user' }" <el-link @click.native="dialog.save = { mode: 'view', row, tabId: 'user' }"
>{{ statistics.roleId?.find((x) => x.key.roleId === row.id.toString())?.value ?? '...' }} >{{ statistics.roleId?.find((x) => x.key.roleId === row.id.toString())?.value ?? '0' }}
</el-link> </el-link>
</template> </template>
</el-table-column> </el-table-column>

View File

@ -79,7 +79,7 @@
:theme="this.$TOOL.data.get('APP_SET_DARK') || this.$CONFIG.APP_SET_DARK ? 'github_dark' : 'github'" :theme="this.$TOOL.data.get('APP_SET_DARK') || this.$CONFIG.APP_SET_DARK ? 'github_dark' : 'github'"
lang="json" lang="json"
style="height: 30rem; width: 100%" /> style="height: 30rem; width: 100%" />
<el-button @click="form.dashboardLayout = jsonFormat(form.dashboardLayout)" type="text" <el-button @click="form.dashboardLayout = jsonFormat(form.dashboardLayout)" link type="primary"
>{{ $t('JSON 格式化') }} >{{ $t('JSON 格式化') }}
</el-button> </el-button>
</el-form-item> </el-form-item>

View File

@ -189,6 +189,12 @@ export default {
}, },
}, },
async created() { async created() {
if (this.roleId) {
this.query.filter.roleId = this.roleId
}
if (this.deptId) {
this.query.filter.deptId = this.deptId
}
const res = await this.$API.sys_dept.query.post({}) const res = await this.$API.sys_dept.query.post({})
this.deptTree = [ this.deptTree = [
@ -198,13 +204,6 @@ export default {
children: res.data, children: res.data,
}, },
] ]
if (this.roleId) {
this.query.filter.roleId = this.roleId
}
if (this.deptId) {
this.query.filter.deptId = this.deptId
}
}, },
data() { data() {
return { return {