Commit 583921112bb36e6a55c280dced81c4c33eb65586

Authored by xingyu
1 parent 227e11f9

fix: todo

yudao-ui-admin-vue3/src/api/infra/fileConfig/index.ts
... ... @@ -16,7 +16,7 @@ export interface ConfigType {
16 16 export interface FileConfigVO {
17 17 id: number
18 18 name: string
19   - storage: string
  19 + storage: number
20 20 master: boolean
21 21 visible: boolean
22 22 config: ConfigType
... ...
yudao-ui-admin-vue3/src/views/infra/fileConfig/fileConfig.data.ts
... ... @@ -40,14 +40,14 @@ const crudSchemas = reactive<VxeCrudSchema>({
40 40 {
41 41 title: '存储器',
42 42 field: 'storage',
43   - dictType: DICT_TYPE.INFRA_FILE_STORAGE, // TODO @星语:不同存储器,不同表单
  43 + dictType: DICT_TYPE.INFRA_FILE_STORAGE,
44 44 dictClass: 'number',
45 45 isSearch: true
46 46 },
47 47 {
48 48 title: '主配置',
49 49 field: 'master',
50   - dictType: DICT_TYPE.INFRA_BOOLEAN_STRING, // TODO @星语:新增时,不选择主配置
  50 + dictType: DICT_TYPE.INFRA_BOOLEAN_STRING,
51 51 dictClass: 'boolean'
52 52 },
53 53 {
... ...
yudao-ui-admin-vue3/src/views/infra/fileConfig/index.vue
... ... @@ -9,7 +9,7 @@
9 9 preIcon="ep:zoom-in"
10 10 :title="t('action.add')"
11 11 v-hasPermi="['infra:file-config:create']"
12   - @click="handleCreate()"
  12 + @click="handleCreate(formRef)"
13 13 />
14 14 </template>
15 15 <template #actionbtns_default="{ row }">
... ... @@ -53,12 +53,94 @@
53 53 </ContentWrap>
54 54 <XModal v-model="dialogVisible" :title="dialogTitle">
55 55 <!-- 对话框(添加 / 修改) -->
56   - <Form
  56 + <el-form
  57 + ref="formRef"
57 58 v-if="['create', 'update'].includes(actionType)"
58   - :schema="allSchemas.formSchema"
  59 + :model="form"
59 60 :rules="rules"
60   - ref="formRef"
61   - />
  61 + label-width="120px"
  62 + >
  63 + <el-form-item label="配置名" prop="name">
  64 + <el-input v-model="form.name" placeholder="请输入配置名" />
  65 + </el-form-item>
  66 + <el-form-item label="备注" prop="remark">
  67 + <el-input v-model="form.remark" placeholder="请输入备注" />
  68 + </el-form-item>
  69 + <el-form-item label="存储器" prop="storage">
  70 + <el-select v-model="form.storage" placeholder="请选择存储器" :disabled="form.id !== 0">
  71 + <el-option
  72 + v-for="dict in getIntDictOptions(DICT_TYPE.INFRA_FILE_STORAGE)"
  73 + :key="dict.value"
  74 + :label="dict.label"
  75 + :value="dict.value"
  76 + />
  77 + </el-select>
  78 + </el-form-item>
  79 + <!-- DB -->
  80 + <!-- Local / FTP / SFTP -->
  81 + <el-form-item
  82 + v-if="form.storage >= 10 && form.storage <= 12"
  83 + label="基础路径"
  84 + prop="config.basePath"
  85 + >
  86 + <el-input v-model="form.config.basePath" placeholder="请输入基础路径" />
  87 + </el-form-item>
  88 + <el-form-item
  89 + v-if="form.storage >= 11 && form.storage <= 12"
  90 + label="主机地址"
  91 + prop="config.host"
  92 + >
  93 + <el-input v-model="form.config.host" placeholder="请输入主机地址" />
  94 + </el-form-item>
  95 + <el-form-item
  96 + v-if="form.storage >= 11 && form.storage <= 12"
  97 + label="主机端口"
  98 + prop="config.port"
  99 + >
  100 + <el-input-number :min="0" v-model="form.config.port" placeholder="请输入主机端口" />
  101 + </el-form-item>
  102 + <el-form-item
  103 + v-if="form.storage >= 11 && form.storage <= 12"
  104 + label="用户名"
  105 + prop="config.username"
  106 + >
  107 + <el-input v-model="form.config.username" placeholder="请输入密码" />
  108 + </el-form-item>
  109 + <el-form-item
  110 + v-if="form.storage >= 11 && form.storage <= 12"
  111 + label="密码"
  112 + prop="config.password"
  113 + >
  114 + <el-input v-model="form.config.password" placeholder="请输入密码" />
  115 + </el-form-item>
  116 + <el-form-item v-if="form.storage === 11" label="连接模式" prop="config.mode">
  117 + <el-radio-group v-model="form.config.mode">
  118 + <el-radio key="Active" label="Active">主动模式</el-radio>
  119 + <el-radio key="Passive" label="Passive">主动模式</el-radio>
  120 + </el-radio-group>
  121 + </el-form-item>
  122 + <!-- S3 -->
  123 + <el-form-item v-if="form.storage === 20" label="节点地址" prop="config.endpoint">
  124 + <el-input v-model="form.config.endpoint" placeholder="请输入节点地址" />
  125 + </el-form-item>
  126 + <el-form-item v-if="form.storage === 20" label="存储 bucket" prop="config.bucket">
  127 + <el-input v-model="form.config.bucket" placeholder="请输入 bucket" />
  128 + </el-form-item>
  129 + <el-form-item v-if="form.storage === 20" label="accessKey" prop="config.accessKey">
  130 + <el-input v-model="form.config.accessKey" placeholder="请输入 accessKey" />
  131 + </el-form-item>
  132 + <el-form-item v-if="form.storage === 20" label="accessSecret" prop="config.accessSecret">
  133 + <el-input v-model="form.config.accessSecret" placeholder="请输入 accessSecret" />
  134 + </el-form-item>
  135 + <!-- 通用 -->
  136 + <el-form-item v-if="form.storage === 20" label="自定义域名">
  137 + <!-- 无需参数校验,所以去掉 prop -->
  138 + <el-input v-model="form.config.domain" placeholder="请输入自定义域名" />
  139 + </el-form-item>
  140 + <el-form-item v-else-if="form.storage" label="自定义域名" prop="config.domain">
  141 + <el-input v-model="form.config.domain" placeholder="请输入自定义域名" />
  142 + </el-form-item>
  143 + </el-form>
62 144 <!-- 对话框(详情) -->
63 145 <Descriptions
64 146 v-if="actionType === 'detail'"
... ... @@ -73,7 +155,7 @@
73 155 type="primary"
74 156 :title="t('action.save')"
75 157 :loading="actionLoading"
76   - @click="submitForm()"
  158 + @click="submitForm(formRef)"
77 159 />
78 160 <!-- 按钮:关闭 -->
79 161 <XButton :loading="actionLoading" :title="t('dialog.close')" @click="dialogVisible = false" />
... ... @@ -82,15 +164,26 @@
82 164 </template>
83 165 <script setup lang="ts" name="FileConfig">
84 166 // 全局相关的 import
85   -import { ref, unref } from 'vue'
  167 +import { reactive, ref } from 'vue'
  168 +import {
  169 + ElForm,
  170 + ElFormItem,
  171 + FormInstance,
  172 + ElSelect,
  173 + ElOption,
  174 + ElInput,
  175 + ElInputNumber,
  176 + ElRadio,
  177 + ElRadioGroup
  178 +} from 'element-plus'
86 179 import { useI18n } from '@/hooks/web/useI18n'
87 180 import { useMessage } from '@/hooks/web/useMessage'
88 181 import { useVxeGrid } from '@/hooks/web/useVxeGrid'
89 182 import { VxeGridInstance } from 'vxe-table'
90   -import { FormExpose } from '@/components/Form'
91 183 // 业务相关的 import
92 184 import * as FileConfigApi from '@/api/infra/fileConfig'
93 185 import { rules, allSchemas } from './fileConfig.data'
  186 +import { getIntDictOptions, DICT_TYPE } from '@/utils/dict'
94 187  
95 188 const { t } = useI18n() // 国际化
96 189 const message = useMessage() // 消息弹窗
... ... @@ -107,8 +200,30 @@ const actionLoading = ref(false) // 遮罩层
107 200 const actionType = ref('') // 操作按钮的类型
108 201 const dialogVisible = ref(false) // 是否显示弹出层
109 202 const dialogTitle = ref('edit') // 弹出层标题
110   -const formRef = ref<FormExpose>() // 表单 Ref
  203 +const formRef = ref<FormInstance>() // 表单 Ref
111 204 const detailData = ref() // 详情 Ref
  205 +let form = reactive<FileConfigApi.FileConfigVO>({
  206 + id: 0,
  207 + name: '',
  208 + storage: 0,
  209 + master: false,
  210 + visible: false,
  211 + config: {
  212 + basePath: '',
  213 + host: '',
  214 + port: '',
  215 + username: '',
  216 + password: '',
  217 + mode: '',
  218 + endpoint: '',
  219 + bucket: '',
  220 + accessKey: '',
  221 + accessSecret: '',
  222 + domain: ''
  223 + },
  224 + remark: '',
  225 + createTime: ''
  226 +})
112 227 // 设置标题
113 228 const setDialogTile = (type: string) => {
114 229 dialogTitle.value = t('action.' + type)
... ... @@ -117,16 +232,17 @@ const setDialogTile = (type: string) =&gt; {
117 232 }
118 233  
119 234 // 新增操作
120   -const handleCreate = () => {
  235 +const handleCreate = (formEl: FormInstance | undefined) => {
121 236 setDialogTile('create')
  237 + formEl?.resetFields()
122 238 }
123 239  
124 240 // 修改操作
125 241 const handleUpdate = async (rowId: number) => {
126   - setDialogTile('update')
127 242 // 设置数据
128 243 const res = await FileConfigApi.getFileConfigApi(rowId)
129   - unref(formRef)?.setValues(res)
  244 + form = res
  245 + setDialogTile('update')
130 246 }
131 247  
132 248 // 详情操作
... ... @@ -153,20 +269,18 @@ const handleDelete = async (rowId: number) =&gt; {
153 269 }
154 270  
155 271 // 提交按钮
156   -const submitForm = async () => {
157   - const elForm = unref(formRef)?.getElFormRef()
158   - if (!elForm) return
159   - elForm.validate(async (valid) => {
  272 +const submitForm = async (formEl: FormInstance | undefined) => {
  273 + if (!formEl) return
  274 + formEl.validate(async (valid) => {
160 275 if (valid) {
161 276 actionLoading.value = true
162 277 // 提交请求
163 278 try {
164   - const data = unref(formRef)?.formModel as FileConfigApi.FileConfigVO
165 279 if (actionType.value === 'create') {
166   - await FileConfigApi.createFileConfigApi(data)
  280 + await FileConfigApi.createFileConfigApi(form)
167 281 message.success(t('common.createSuccess'))
168 282 } else {
169   - await FileConfigApi.updateFileConfigApi(data)
  283 + await FileConfigApi.updateFileConfigApi(form)
170 284 message.success(t('common.updateSuccess'))
171 285 }
172 286 dialogVisible.value = false
... ...
yudao-ui-admin-vue3/src/views/infra/job/index.vue
... ... @@ -100,7 +100,9 @@
100 100 <template #monitorTimeout="{ row }">
101 101 <span>{{ row.monitorTimeout > 0 ? row.monitorTimeout + ' 毫秒' : '未开启' }}</span>
102 102 </template>
103   - <!-- TODO @星语:有个【后续执行时间】字段:2022-11-26 23:03:16; 2022-11-26 23:03:17; 2022-11-26 23:03:18; 2022-11-26 23:03:19; 2022-11-26 23:03:20 -->
  103 + <template #nextTimes>
  104 + <span>{{ Array.from(nextTimes, (x) => parseTime(x)).join('; ') }}</span>
  105 + </template>
104 106 </Descriptions>
105 107 <!-- 操作按钮 -->
106 108 <template #footer>
... ... @@ -151,6 +153,7 @@ const dialogTitle = ref(&#39;edit&#39;) // 弹出层标题
151 153 const formRef = ref<FormExpose>() // 表单 Ref
152 154 const detailRef = ref() // 详情 Ref
153 155 const cronExpression = ref('')
  156 +const nextTimes = ref([])
154 157 const shortcuts = ref([
155 158 {
156 159 text: '每天8点和12点 (自定义追加)',
... ... @@ -169,10 +172,12 @@ const handleCreate = () =&gt; {
169 172 cronExpression.value = ''
170 173 setDialogTile('create')
171 174 }
  175 +
172 176 // 导出操作
173 177 const handleExport = async () => {
174 178 await exportList(xGrid, '定时任务.xls')
175 179 }
  180 +
176 181 // 修改操作
177 182 const handleUpdate = async (rowId: number) => {
178 183 setDialogTile('update')
... ... @@ -187,8 +192,57 @@ const handleDetail = async (rowId: number) =&gt; {
187 192 // 设置数据
188 193 const res = await JobApi.getJobApi(rowId)
189 194 detailRef.value = res
  195 + // 后续执行时长
  196 + const jobNextTime = await JobApi.getJobNextTimesApi(rowId)
  197 + nextTimes.value = jobNextTime
190 198 setDialogTile('detail')
191 199 }
  200 +
  201 +const parseTime = (time) => {
  202 + if (!time) {
  203 + return null
  204 + }
  205 + const format = '{y}-{m}-{d} {h}:{i}:{s}'
  206 + let date
  207 + if (typeof time === 'object') {
  208 + date = time
  209 + } else {
  210 + if (typeof time === 'string' && /^[0-9]+$/.test(time)) {
  211 + time = parseInt(time)
  212 + } else if (typeof time === 'string') {
  213 + time = time
  214 + .replace(new RegExp(/-/gm), '/')
  215 + .replace('T', ' ')
  216 + .replace(new RegExp(/\.[\d]{3}/gm), '')
  217 + }
  218 + if (typeof time === 'number' && time.toString().length === 10) {
  219 + time = time * 1000
  220 + }
  221 + date = new Date(time)
  222 + }
  223 + const formatObj = {
  224 + y: date.getFullYear(),
  225 + m: date.getMonth() + 1,
  226 + d: date.getDate(),
  227 + h: date.getHours(),
  228 + i: date.getMinutes(),
  229 + s: date.getSeconds(),
  230 + a: date.getDay()
  231 + }
  232 + const time_str = format.replace(/{(y|m|d|h|i|s|a)+}/g, (result, key) => {
  233 + let value = formatObj[key]
  234 + // Note: getDay() returns 0 on Sunday
  235 + if (key === 'a') {
  236 + return ['日', '一', '二', '三', '四', '五', '六'][value]
  237 + }
  238 + if (result.length > 0 && value < 10) {
  239 + value = '0' + value
  240 + }
  241 + return value || 0
  242 + })
  243 + return time_str
  244 +}
  245 +
192 246 // 删除操作
193 247 const handleDelete = async (rowId: number) => {
194 248 await deleteData(xGrid, rowId)
... ...
yudao-ui-admin-vue3/src/views/infra/job/job.data.ts
... ... @@ -49,6 +49,12 @@ const crudSchemas = reactive&lt;VxeCrudSchema&gt;({
49 49 field: 'cronExpression'
50 50 },
51 51 {
  52 + title: '后续执行时间',
  53 + field: 'nextTimes',
  54 + isTable: false,
  55 + isForm: false
  56 + },
  57 + {
52 58 title: '重试次数',
53 59 field: 'retryCount',
54 60 isTable: false
... ...