feat: 框架代码同步 (#158)

[skip ci]

Co-authored-by: tk <fiyne1a@dingtalk.com>
This commit is contained in:
2024-07-22 12:58:10 +08:00
committed by GitHub
parent 60ec6ea2c1
commit 1a28e8d5a6
107 changed files with 1256 additions and 664 deletions

View File

@ -11,14 +11,14 @@
"dependencies": {
"@element-plus/icons-vue": "^2.3.1",
"ace-builds": "^1.35.2",
"aieditor": "^1.0.12",
"aieditor": "^1.0.13",
"axios": "^1.7.2",
"clipboard": "^2.0.11",
"core-js": "^3.37.1",
"cropperjs": "^1.6.2",
"crypto-js": "^4.2.0",
"echarts": "^5.5.1",
"element-plus": "^2.7.6",
"element-plus": "^2.7.7",
"json-bigint": "^1.0.0",
"json5-to-table": "^0.1.8",
"markdown-it": "^14.1.0",
@ -38,11 +38,11 @@
},
"devDependencies": {
"@vitejs/plugin-vue": "^5.0.5",
"prettier": "^3.3.2",
"prettier": "^3.3.3",
"prettier-plugin-organize-attributes": "^1.0.0",
"sass": "^1.77.6",
"terser": "^5.31.1",
"vite": "^5.3.3"
"sass": "^1.77.8",
"terser": "^5.31.3",
"vite": "^5.3.4"
},
"browserslist": [
"> 1%",

View File

@ -1,7 +1,10 @@
<template>
<el-table-column v-bind="$attrs">
<template #default="{ row }">
<div @click="click($TOOL.getNestedProperty(row, $attrs.prop))" class="avatar">
<div
:style="{ display: $TOOL.getNestedProperty(row, $attrs.prop) ? 'flex' : 'none' }"
@click="click($TOOL.getNestedProperty(row, $attrs.prop))"
class="avatar">
<el-avatar v-if="$TOOL.getNestedProperty(row, $attrs.nestProp)" :src="getAvatar(row, $attrs.nestProp)" size="small"></el-avatar>
<div>
<p>{{ $TOOL.getNestedProperty(row, $attrs.nestProp) }}</p>

View File

@ -94,7 +94,7 @@ export default {
return {
dateShortCuts: [
{
text: this.$t('今'),
text: this.$t('今'),
value: () => {
const start = new Date()
start.setHours(0, 0, 0, 0)
@ -102,7 +102,7 @@ export default {
},
},
{
text: this.$t('昨'),
text: this.$t('昨'),
value: () => {
const start = new Date()
start.setHours(0, 0, 0, 0)
@ -111,7 +111,17 @@ export default {
},
},
{
text: this.$t('最近三天'),
text: this.$t('后退一日'),
value: () => {
try {
const start = new Date(new Date(this.form.dy.createdTime[0]) - 3600 * 1000 * 24)
const end = new Date(new Date(this.form.dy.createdTime[1]) - 3600 * 1000 * 24)
return [start, end]
} catch {}
},
},
{
text: this.$t('最近三日'),
value: () => {
const start = new Date()
start.setHours(0, 0, 0, 0)
@ -342,6 +352,16 @@ export default {
return [start, end]
},
},
{
text: this.$t('后退一时'),
value: () => {
try {
const start = new Date(new Date(this.form.dy.createdTime[0]) - 3600 * 1000)
const end = new Date(new Date(this.form.dy.createdTime[1]) - 3600 * 1000)
return [start, end]
} catch {}
},
},
{
text: this.$t('昨日此时'),
value: () => {

View File

@ -349,9 +349,9 @@ export default {
两次输入密码不一致: 'The two passwords entered are inconsistent',
必须提供当前登录用户密码才能进行更改: 'You must provide the current login user password to change',
设置密码: 'Set password',
: 'Today',
: 'Yesterday',
最近三: 'Last 3 days',
: 'Today',
: 'Yesterday',
最近三: 'Last 3 days',
最近一周: 'Last week',
最近一月: 'Last month',
最近三月: 'Last 3 months',
@ -484,4 +484,6 @@ export default {
'访问趋势(Today)': 'Access trend (Today)',
'作业分布(Today)': 'Job distribution (Today)',
'作业趋势(Today)': 'Job trend (Today)',
后退一时: 'Back an hour',
后退一日: 'Back a day',
}

View File

@ -348,9 +348,9 @@ export default {
两次输入密码不一致: '两次输入密码不一致',
必须提供当前登录用户密码才能进行更改: '必须提供当前登录用户密码才能进行更改',
设置密码: '设置密码',
: '今',
: '昨',
最近三: '最近三',
: '今',
: '昨',
最近三: '最近三',
最近一周: '最近一周',
最近一月: '最近一月',
最近三月: '最近三月',
@ -481,4 +481,6 @@ export default {
'访问趋势(Today)': '访问趋势(Today)',
'作业分布(Today)': '作业分布(Today)',
'作业趋势(Today)': '作业趋势(Today)',
后退一时: '后退一时',
后退一日: '后退一日',
}

View File

@ -505,6 +505,10 @@ textarea {
width: 100%;
}
.h100p {
height: 100%;
}
.text-center {
text-align: center;
}
@ -527,4 +531,24 @@ textarea {
.font-monospace {
font-family: 'Lucida Console', 'Microsoft YaHei', monospace;
}
.trace-log {
font-family: 'Lucida Console', 'Microsoft YaHei', monospace;
&:after {
content: '';
margin: 2rem 0;
border-bottom: var(--el-color-primary) 1px dashed;
display: block;
}
.w15 {
font-weight: bold;
}
}
.keywords-highlight {
background-color: yellow;
color: var(--el-color-black);
}

View File

@ -251,6 +251,15 @@ tool.groupSeparator = function (num) {
tool.unicodeDecode = function (str) {
return str.replace(/\\u([0-9a-fA-F]{4})/g, (match, grp) => String.fromCharCode(parseInt(grp, 16)))
}
// 高亮关键词
tool.highLightKeywords = function (str) {
console.error(str)
var ret = str
.replace(new RegExp('(Body)', 'gi'), '<span class=keywords-highlight>$1</span>')
.replace(new RegExp('(http://cloud_code_adm_api.*?),', 'gi'), '<span class=keywords-highlight>$1</span>')
console.error(ret)
return ret
}
// 属性排序
tool.sortProperties = function (obj) {
const sortedKeys = Object.keys(obj).sort()

View File

@ -6,16 +6,13 @@
file: 'sys_job',
name: 'getRecordBarChart',
label: '今日',
value: [tool.dateFormat(new Date(), 'yyyy-MM-dd'), tool.dateFormat(new Date(), 'yyyy-MM-dd')],
value: ['DateTime.Now.Date', 'DateTime.Now.Date.AddDays(1)'],
},
{
file: 'sys_job',
name: 'getRecordBarChart',
label: '昨日',
value: [
tool.dateFormat(new Date().setDate(new Date().getDate() - 1), 'yyyy-MM-dd'),
tool.dateFormat(new Date().setDate(new Date().getDate() - 1), 'yyyy-MM-dd'),
],
value: ['DateTime.Now.Date.AddDays(-1)', 'DateTime.Now.Date'],
},
]"
height="20rem"></chart-bar>

View File

@ -6,16 +6,13 @@
file: 'sys_log',
name: 'getBarChart',
label: '今日',
value: [tool.dateFormat(new Date(), 'yyyy-MM-dd'), tool.dateFormat(new Date(), 'yyyy-MM-dd')],
value: ['DateTime.Now.Date', 'DateTime.Now.Date.AddDays(1)'],
},
{
file: 'sys_log',
name: 'getBarChart',
label: '昨日',
value: [
tool.dateFormat(new Date().setDate(new Date().getDate() - 1), 'yyyy-MM-dd'),
tool.dateFormat(new Date().setDate(new Date().getDate() - 1), 'yyyy-MM-dd'),
],
value: ['DateTime.Now.Date.AddDays(-1)', 'DateTime.Now.Date'],
},
]"
height="20rem"></chart-bar>

View File

@ -113,25 +113,23 @@ export default {
return table
},
},
created() {
if (this.keywords) {
this.query.keywords = this.keywords
}
this.query.dynamicFilter.filters.push({
field: 'enabled',
operator: 'eq',
value: true,
})
},
created() {},
data() {
return {
dialog: {},
loading: false,
query: {
dynamicFilter: {
filters: [],
filters: [
{
field: 'enabled',
operator: 'eq',
value: true,
},
],
},
filter: {},
keywords: this.keywords,
},
selection: [],
}

View File

@ -60,7 +60,7 @@ export default {
form: {
enabled: true,
},
loading: false,
loading: true,
mode: 'add',
//验证规则
rules: {

View File

@ -124,25 +124,23 @@ export default {
return table
},
},
created() {
if (this.keywords) {
this.query.keywords = this.keywords
}
this.query.dynamicFilter.filters.push({
field: 'enabled',
operator: 'eq',
value: true,
})
},
created() {},
data() {
return {
dialog: {},
loading: false,
query: {
dynamicFilter: {
filters: [],
filters: [
{
field: 'enabled',
operator: 'eq',
value: true,
},
],
},
filter: {},
keywords: this.keywords,
},
selection: [],
}

View File

@ -66,7 +66,7 @@ export default {
},
//表单数据
form: { enabled: true, sort: 100 },
loading: false,
loading: true,
mode: 'add',
//验证规则
rules: {

View File

@ -64,11 +64,7 @@ export default {
saveDialog,
},
computed: {},
created() {
if (this.keywords) {
this.query.keywords = this.keywords
}
},
created() {},
data() {
return {
data: [],
@ -81,6 +77,7 @@ export default {
filters: [],
},
filter: {},
keywords: this.keywords,
},
}
},
@ -89,7 +86,7 @@ export default {
// 获取字典目录
async getData() {
this.loading = true
const res = await this.$API.sys_dic.queryCatalog.post()
const res = await this.$API.sys_dic.queryCatalog.post({ prop: 'name', order: 'ascending' })
this.loading = false
this.data = res.data

View File

@ -87,11 +87,7 @@ export default {
return table
},
},
created() {
if (this.keywords) {
this.query.keywords = this.keywords
}
},
created() {},
data() {
return {
dialog: {},
@ -101,6 +97,7 @@ export default {
filters: [],
},
filter: {},
keywords: this.keywords,
},
selection: [],
}

View File

@ -40,7 +40,7 @@ export default {
return {
//表单数据
form: {},
loading: false,
loading: true,
mode: 'add',
//验证规则
rules: {

View File

@ -24,7 +24,7 @@ export default {
return {
//表单数据
form: {},
loading: false,
loading: true,
mode: 'add',
//验证规则
rules: {

View File

@ -181,6 +181,12 @@
icon: 'el-icon-video-play',
click: execute,
},
{
icon: 'el-icon-document-copy',
confirm: true,
title: '复制作业',
click: copyJob,
},
{
icon: 'el-icon-delete',
confirm: true,
@ -191,7 +197,7 @@
)
"
:vue="this"
width="200" />
width="220" />
</sc-table>
</el-main>
</el-container>
@ -224,25 +230,23 @@ export default {
return table
},
},
created() {
if (this.keywords || this.$route.query.keywords) {
this.query.keywords = this.keywords || this.$route.query.keywords
}
this.query.dynamicFilter.filters.push({
field: 'enabled',
operator: 'eq',
value: true,
})
},
created() {},
data() {
return {
dialog: {},
loading: false,
query: {
dynamicFilter: {
filters: [],
filters: [
{
field: 'enabled',
operator: 'eq',
value: true,
},
],
},
filter: {},
keywords: this.keywords || this.$route.query.keywords,
},
selection: [],
timer: null,
@ -250,6 +254,19 @@ export default {
},
inject: ['reload'],
methods: {
async copyJob(row) {
let loading = this.$loading()
try {
const res = await this.$API.sys_job.create.post(Object.assign({}, row, { id: 0, jobName: row.jobName + '-copy' }))
if (res.data) {
this.$message.success(this.$t('操作成功'))
} else {
this.$message.error(this.$t('操作失败'))
}
this.$refs.table.refresh()
} catch {}
loading?.close()
},
async setEnabled(enabled) {
let loading
try {

View File

@ -58,6 +58,22 @@
<el-form-item :label="$t('请求的网络地址')" prop="requestUrl">
<el-input v-model="form.requestUrl" clearable />
</el-form-item>
<el-form-item :label="$t('随机延时')">
<div class="flex gap05">
<el-input
v-model="form.randomDelayBegin"
:placeholder="$t('起始值(毫秒)')"
class="w15"
clearable
oninput="value=value.replace(/[^0-9]/g,'')" />
<el-input
v-model="form.randomDelayEnd"
:placeholder="$t('结束值(毫秒)')"
class="w15"
clearable
oninput="value=value.replace(/[^0-9]/g,'')" />
</div>
</el-form-item>
<el-form-item v-if="mode === 'view'" :label="$t('作业状态')" prop="status">
<el-input v-model="form.status" clearable />
</el-form-item>
@ -127,7 +143,7 @@ export default {
requestHeader: `{ "Content-Type": "application/json" }`,
requestBody: '{}',
},
loading: false,
loading: true,
mode: 'add',
//验证规则
rules: {

View File

@ -54,7 +54,7 @@
}
}
"
:context-menus="['id', 'duration', 'httpMethod', 'requestUrl', 'httpStatusCode', 'createdTime', 'jobId']"
:context-menus="['id', 'duration', 'httpMethod', 'requestUrl', 'httpStatusCode', 'createdTime', 'jobId', 'responseBody']"
:default-sort="{ prop: 'createdTime', order: 'descending' }"
:export-api="$API.sys_job.exportRecord"
:params="query"
@ -153,9 +153,6 @@ export default {
},
},
created() {
if (this.keywords) {
this.query.keywords = this.keywords
}
if (this.statusCodes) {
this.query.dynamicFilter.filters.push({
logic: 'or',
@ -184,6 +181,7 @@ export default {
],
},
filter: {},
keywords: this.keywords,
},
}
},

View File

@ -51,7 +51,7 @@ export default {
return {
//表单数据
form: {},
loading: false,
loading: true,
mode: 'add',
//验证规则
rules: {},

View File

@ -47,7 +47,6 @@
:params="query"
:query-api="$API.sys_log.pagedQuery"
:vue="this"
@row-click="rowClick"
ref="table"
remote-filter
remote-sort
@ -60,14 +59,23 @@
{{ row.httpStatusCode === 200 ? '成功' : '失败' }}
</template>
</el-table-column>
<el-table-column :label="$t('登录名')" prop="loginName" width="150" />
<el-table-column :label="$t('登录名')" prop="detail.loginName" width="150" />
<el-table-column :label="$t('客户端IP')" prop="createdClientIp" show-overflow-tooltip sortable="custom" width="200">
<template #default="{ row }">
<na-ip :ip="row.createdClientIp"></na-ip>
</template>
</el-table-column>
<el-table-column :label="$t('操作系统')" align="center" prop="os" width="150" />
<el-table-column :label="$t('用户代理')" prop="createdUserAgent" show-overflow-tooltip sortable="custom" />
<el-table-column :label="$t('操作系统')" align="center" prop="detail.os" width="150" />
<el-table-column :label="$t('用户代理')" prop="detail.createdUserAgent" show-overflow-tooltip sortable="custom" />
<na-col-operation
:buttons="[
{
icon: 'el-icon-view',
click: rowClick,
},
]"
:vue="this"
width="70" />
</sc-table>
</el-main>
</el-container>
@ -84,13 +92,10 @@ export default {
},
computed: {},
created() {
if (this.keywords) {
this.query.keywords = this.keywords
}
this.query.dynamicFilter.filters.push({
field: 'apiId',
field: 'apiPathCrc32',
operator: 'eq',
value: 'api/sys/user/login.by.pwd',
value: '1290209789',
})
},
data() {
@ -110,6 +115,7 @@ export default {
],
},
filter: {},
keywords: this.keywords,
},
selection: [],
}
@ -124,11 +130,11 @@ export default {
},
//搜索
onSearch(form) {
if (this.query.dynamicFilter.filters.findIndex((x) => x.field === 'apiId') < 0) {
if (this.query.dynamicFilter.filters.findIndex((x) => x.field === 'apiPathCrc32') < 0) {
this.query.dynamicFilter.filters.push({
field: 'apiId',
field: 'apiPathCrc32',
operator: 'eq',
value: 'api/sys/user/login.by.pwd',
value: '1290209789',
})
}
if (Array.isArray(form.dy.createdTime)) {
@ -174,7 +180,7 @@ export default {
type: 'root',
})
}
this.$refs.search.form.dy.apiId = 'api/sys/user/login.by.pwd'
this.$refs.search.form.dy['apiPathCrc32'] = '1290209789'
this.$refs.search.form.dy.createdTime = [
`${this.$TOOL.dateFormat(new Date(), 'yyyy-MM-dd')} 00:00:00`,
`${this.$TOOL.dateFormat(new Date(), 'yyyy-MM-dd')} 00:00:00`,

View File

@ -37,7 +37,7 @@
},
{
type: 'cascader',
field: ['dy', 'apiId'],
field: ['dy', 'api.id'],
api: $API.sys_api.query,
props: { label: 'summary', value: 'id', checkStrictly: true, expandTrigger: 'hover', emitPath: false },
placeholder: $t('请求服务'),
@ -62,7 +62,7 @@
</el-header>
<el-main class="nopadding">
<sc-table
:context-menus="['id', 'httpStatusCode', 'apiId', 'userId', 'method', 'duration', 'createdClientIp', 'createdTime']"
:context-menus="['id', 'httpStatusCode', 'apiPathCrc32', 'ownerId', 'httpMethod', 'duration', 'createdClientIp', 'createdTime']"
:context-opers="[]"
:default-sort="{ prop: 'createdTime', order: 'descending' }"
:export-api="$API.sys_log.export"
@ -82,21 +82,21 @@
</template>
</el-table-column>
<el-table-column :label="$t('请求服务')" align="center">
<el-table-column :label="$t('路径')" prop="apiId" show-overflow-tooltip sortable="custom">
<el-table-column :label="$t('路径')" prop="apiPathCrc32" show-overflow-tooltip sortable="custom">
<template #default="{ row }">
<p>{{ row.apiId }}</p>
<p>{{ row.apiSummary }}</p>
<p>{{ row.api.id }}</p>
<p>{{ row.api.summary }}</p>
</template>
</el-table-column>
<el-table-column :label="$t('方法')" align="center" prop="method" sortable="custom" width="100">
<el-table-column :label="$t('方法')" align="center" prop="httpMethod" sortable="custom" width="100">
<template #default="{ row }">
<sc-status-indicator
:style="`background: #${Math.abs(this.$TOOL.crypto.hashCode(row.method)).toString(16).substring(0, 6)}`" />
{{ row.method }}
:style="`background: #${Math.abs(this.$TOOL.crypto.hashCode(row.httpMethod)).toString(16).substring(0, 6)}`" />
{{ row.httpMethod.toUpperCase() }}
</template>
</el-table-column>
<el-table-column
:formatter="(row) => `${$TOOL.groupSeparator((row.duration / 1000).toFixed(0))} ms`"
:formatter="(row) => `${$TOOL.groupSeparator(row.duration.toFixed(0))} ms`"
:label="$t('耗时')"
align="right"
prop="duration"
@ -108,9 +108,9 @@
v-auth="'sys/log/operation/user'"
:label="$t('用户')"
header-align="center"
nestProp="user.userName"
nestProp2="user.id"
prop="userId"
nestProp="owner.userName"
nestProp2="owner.id"
prop="ownerId"
sortable="custom"
width="170"></na-col-user>
<el-table-column :label="$t('客户端IP')" prop="createdClientIp" show-overflow-tooltip sortable="custom" width="200">
@ -118,7 +118,6 @@
<na-ip :ip="row.createdClientIp"></na-ip>
</template>
</el-table-column>
<el-table-column :label="$t('操作系统')" align="center" prop="os" width="150" />
<na-col-operation
:buttons="[
{
@ -144,11 +143,8 @@ export default {
},
computed: {},
created() {
if (this.keywords) {
this.query.keywords = this.keywords
}
if (this.userId) {
this.query.dynamicFilter.filters.push({ field: 'userId', operator: 'eq', value: this.userId })
if (this.ownerId) {
this.query.dynamicFilter.filters.push({ field: 'ownerId', operator: 'eq', value: this.ownerId })
}
},
data() {
@ -168,6 +164,7 @@ export default {
],
},
filter: {},
keywords: this.keywords,
},
selection: [],
}
@ -197,19 +194,19 @@ export default {
}),
})
}
if (typeof form.dy.apiId === 'string' && form.dy.apiId.trim() !== '') {
if (typeof form.dy['api.id'] === 'string' && form.dy['api.id'].trim() !== '') {
this.query.dynamicFilter.filters.push({
field: 'apiId',
field: 'api.id',
operator: 'eq',
value: form.dy.apiId,
value: form.dy['api.id'],
})
}
if (typeof form.dy.userId === 'number' && form.dy.userId !== 0) {
if (typeof form.dy.ownerId === 'number' && form.dy.ownerId !== 0) {
this.query.dynamicFilter.filters.push({
field: 'userId',
field: 'ownerId',
operator: 'eq',
value: form.dy.userId,
value: form.dy.ownerId,
})
}
@ -250,10 +247,10 @@ export default {
})
}
if (this.userId) {
if (this.ownerId) {
this.$refs.search.keeps.push({
field: 'userId',
value: this.userId,
field: 'ownerId',
value: this.ownerId,
type: 'dy',
})
}
@ -268,7 +265,7 @@ export default {
type: 'dy',
})
},
props: ['keywords', 'userId'],
props: ['keywords', 'ownerId'],
watch: {},
}
</script>

View File

@ -116,11 +116,7 @@ export default {
return table
},
},
created() {
if (this.keywords) {
this.query.keywords = this.keywords
}
},
created() {},
data() {
return {
dialog: {},
@ -130,6 +126,7 @@ export default {
filters: [],
},
filter: {},
keywords: this.keywords,
},
selection: [],
}

View File

@ -87,7 +87,7 @@ export default {
roleIds: [],
deptIds: [],
},
loading: false,
loading: true,
mode: 'add',
//验证规则
rules: {

View File

@ -170,25 +170,23 @@ export default {
return table
},
},
created() {
if (this.keywords) {
this.query.keywords = this.keywords
}
this.query.dynamicFilter.filters.push({
field: 'enabled',
operator: 'eq',
value: true,
})
},
created() {},
data() {
return {
dialog: {},
loading: false,
query: {
dynamicFilter: {
filters: [],
filters: [
{
field: 'enabled',
operator: 'eq',
value: true,
},
],
},
filter: {},
keywords: this.keywords,
},
selection: [],
}

View File

@ -118,7 +118,7 @@ export default {
return {
//表单数据
form: { displayDashboard: false, dashboardLayout: this.jsonFormat(config.APP_SET_HOME_GRID), sort: 100, enabled: true },
loading: false,
loading: true,
mode: 'add',
//验证规则
rules: {

View File

@ -149,20 +149,12 @@ export default {
},
},
created() {
if (this.keywords) {
this.query.keywords = this.keywords
}
if (this.roleId) {
this.query.filter.roleId = this.roleId
}
if (this.deptId) {
this.query.filter.deptId = this.deptId
}
this.query.dynamicFilter.filters.push({
field: 'enabled',
operator: 'eq',
value: true,
})
},
data() {
return {
@ -170,9 +162,16 @@ export default {
loading: false,
query: {
dynamicFilter: {
filters: [],
filters: [
{
field: 'enabled',
operator: 'eq',
value: true,
},
],
},
filter: {},
keywords: this.keywords,
},
selection: [],
}

View File

@ -232,7 +232,7 @@
</el-row>
</el-tab-pane>
<el-tab-pane v-if="mode === 'view'" :label="$t('操作日志')" name="log">
<log v-if="tabId === 'log'" :user-id="form.id"></log>
<log v-if="tabId === 'log'" :owner-id="form.id"></log>
</el-tab-pane>
<el-tab-pane v-if="mode === 'view'" :label="$t('原始数据')">
<json-viewer
@ -270,7 +270,7 @@ export default {
emergencyContactArea: '',
},
},
loading: false,
loading: true,
mode: 'add',
//验证规则
rules: {