This commit is contained in:
bimei 2023-03-06 18:20:20 +08:00
commit ece4cf2760
23 changed files with 235 additions and 54 deletions

19
.env.front Normal file
View File

@ -0,0 +1,19 @@
# 本地开发环境
NODE_ENV=development
VITE_DEV=true
# 请求路径
VITE_BASE_URL='http://api-dashboard.yudao.iocoder.cn'
# 上传路径
VITE_UPLOAD_URL='http://api-dashboard.yudao.iocoder.cn/admin-api/infra/file/upload'
# 接口前缀
VITE_API_BASEPATH=/dev-api
# 接口地址
VITE_API_URL=/admin-api
# 打包路径
VITE_BASE_PATH=/

31
.env.static Normal file
View File

@ -0,0 +1,31 @@
# 开发环境
NODE_ENV=production
VITE_DEV=false
# 请求路径
VITE_BASE_URL='http://localhost:48080'
# 上传路径
VITE_UPLOAD_URL='http://localhost:48080/admin-api/infra/file/upload'
# 接口前缀
VITE_API_BASEPATH=
# 接口地址
VITE_API_URL=/admin-api
# 是否删除debugger
VITE_DROP_DEBUGGER=true
# 是否删除console.log
VITE_DROP_CONSOLE=true
# 是否sourcemap
VITE_SOURCEMAP=false
# 打包路径
VITE_BASE_PATH=/admin-ui-vue3/
# 输出路径
VITE_OUT_DIR=dist-dev

View File

@ -7,10 +7,12 @@
"scripts": { "scripts": {
"i": "pnpm install", "i": "pnpm install",
"dev": "vite --mode base", "dev": "vite --mode base",
"front": "vite --mode front",
"ts:check": "vue-tsc --noEmit", "ts:check": "vue-tsc --noEmit",
"build:pro": "node --max_old_space_size=8000 ./node_modules/vite/bin/vite.js build --mode pro", "build:pro": "node --max_old_space_size=8000 ./node_modules/vite/bin/vite.js build --mode pro",
"build:dev": "node --max_old_space_size=8000 ./node_modules/vite/bin/vite.js build --mode dev", "build:dev": "node --max_old_space_size=8000 ./node_modules/vite/bin/vite.js build --mode dev",
"build:test": "node --max_old_space_size=8000 ./node_modules/vite/bin/vite.js build --mode test", "build:test": "node --max_old_space_size=8000 ./node_modules/vite/bin/vite.js build --mode test",
"build:static": "node --max_old_space_size=8000 ./node_modules/vite/bin/vite.js build --mode static",
"serve:pro": "vite preview --mode pro", "serve:pro": "vite preview --mode pro",
"serve:dev": "vite preview --mode dev", "serve:dev": "vite preview --mode dev",
"serve:test": "vite preview --mode test", "serve:test": "vite preview --mode test",

View File

@ -13,7 +13,6 @@ import { useDesign } from '@/hooks/web/useDesign'
import { XTableProps } from './type' import { XTableProps } from './type'
import { isBoolean, isFunction } from '@/utils/is' import { isBoolean, isFunction } from '@/utils/is'
import styleCss from './style/dark.scss' import styleCss from './style/dark.scss'
import download from '@/utils/download' import download from '@/utils/download'
const { t } = useI18n() const { t } = useI18n()
@ -26,14 +25,13 @@ const prefixCls = getPrefixCls('x-vxe-table')
const attrs = useAttrs() const attrs = useAttrs()
const emit = defineEmits(['register']) const emit = defineEmits(['register'])
const removeStyles = () => { const removeStyles = () => {
var filename = 'cssTheme' const filename = 'cssTheme'
// //
var targetelement = 'style' const targetelement = 'style'
var targetattr = 'id' const targetattr = 'id'
var allsuspects = document.getElementsByTagName(targetelement) let allsuspects = document.getElementsByTagName(targetelement)
for (var i = allsuspects.length; i >= 0; i--) { for (let i = allsuspects.length; i >= 0; i--) {
if ( if (
allsuspects[i] && allsuspects[i] &&
allsuspects[i].getAttribute(targetattr) != null && allsuspects[i].getAttribute(targetattr) != null &&
@ -45,13 +43,12 @@ const removeStyles = () => {
} }
} }
const reImport = () => { const reImport = () => {
var head = document.getElementsByTagName('head')[0] let head = document.getElementsByTagName('head')[0]
var style = document.createElement('style') let style = document.createElement('style')
style.innerText = styleCss style.innerText = styleCss
style.id = 'cssTheme' style.id = 'cssTheme'
head.appendChild(style) head.appendChild(style)
} }
watch( watch(
() => appStore.getIsDark, () => appStore.getIsDark,
() => { () => {

View File

@ -80,7 +80,8 @@ const resetFlowCondition = () => {
if ( if (
bpmnElementSourceRef.value && bpmnElementSourceRef.value &&
bpmnElementSourceRef.value.default && bpmnElementSourceRef.value.default &&
bpmnElementSourceRef.value.default.id === bpmnElement.value.id bpmnElementSourceRef.value.default.id === bpmnElement.value.id &&
flowConditionForm.value.type == 'default'
) { ) {
// //
flowConditionForm.value = { type: 'default' } flowConditionForm.value = { type: 'default' }
@ -176,11 +177,13 @@ onBeforeUnmount(() => {
watch( watch(
() => props.businessObject, () => props.businessObject,
(val) => { (val) => {
if (val) { console.log(val, 'val')
nextTick(() => { nextTick(() => {
resetFlowCondition() resetFlowCondition()
}) })
} },
{
immediate: true
} }
) )
</script> </script>

View File

@ -3,9 +3,21 @@
<!-- 表单设计器 --> <!-- 表单设计器 -->
<fc-designer ref="designer" height="780px"> <fc-designer ref="designer" height="780px">
<template #handle> <template #handle>
<XButton type="primary" title="生成JSON" @click="showJson" />
<XButton type="primary" title="生成Options" @click="showOption" />
<XButton type="primary" :title="t('action.save')" @click="handleSave" /> <XButton type="primary" :title="t('action.save')" @click="handleSave" />
</template> </template>
</fc-designer> </fc-designer>
<Dialog :title="dialogTitle" v-model="dialogVisible1" maxHeight="600">
<div ref="editor" v-if="dialogVisible1">
<XTextButton style="float: right" :title="t('common.copy')" @click="copy(formValue)" />
<el-scrollbar height="580">
<pre>
{{ formValue }}
</pre>
</el-scrollbar>
</div>
</Dialog>
<!-- 表单保存的弹窗 --> <!-- 表单保存的弹窗 -->
<XModal v-model="dialogVisible" title="保存表单"> <XModal v-model="dialogVisible" title="保存表单">
<el-form ref="formRef" :model="formValues" :rules="formRules" label-width="80px"> <el-form ref="formRef" :model="formValues" :rules="formRules" label-width="80px">
@ -48,13 +60,18 @@ import { DICT_TYPE, getIntDictOptions } from '@/utils/dict'
import { CommonStatusEnum } from '@/utils/constants' import { CommonStatusEnum } from '@/utils/constants'
import * as FormApi from '@/api/bpm/form' import * as FormApi from '@/api/bpm/form'
import { encodeConf, encodeFields, setConfAndFields } from '@/utils/formCreate' import { encodeConf, encodeFields, setConfAndFields } from '@/utils/formCreate'
import { useClipboard } from '@vueuse/core'
const { t } = useI18n() // const { t } = useI18n() //
const message = useMessage() // const message = useMessage() //
const { query } = useRoute() // const { query } = useRoute() //
const designer = ref() // const designer = ref() //
const type = ref(-1)
const formValue = ref('')
const dialogTitle = ref('')
const dialogVisible = ref(false) // const dialogVisible = ref(false) //
const dialogVisible1 = ref(false) //
const dialogLoading = ref(false) // const dialogLoading = ref(false) //
const formRef = ref<FormInstance>() const formRef = ref<FormInstance>()
const formRules = reactive({ const formRules = reactive({
@ -98,7 +115,32 @@ const submitForm = async () => {
dialogLoading.value = false dialogLoading.value = false
} }
} }
const showJson = () => {
openModel('生成JSON')
type.value = 0
formValue.value = designer.value.getRule()
}
const showOption = () => {
openModel('生成Options')
type.value = 1
formValue.value = designer.value.getOption()
}
const openModel = (title: string) => {
dialogVisible1.value = true
dialogTitle.value = title
}
/** 复制 **/
const copy = async (text: string) => {
const { copy, copied, isSupported } = useClipboard({ source: text })
if (!isSupported) {
message.error(t('common.copyError'))
} else {
await copy()
if (unref(copied)) {
message.success(t('common.copySuccess'))
}
}
}
// ========== ========== // ========== ==========
onMounted(() => { onMounted(() => {
// //

View File

@ -16,6 +16,7 @@ const crudSchemas = reactive<VxeCrudSchema>({
primaryType: 'id', primaryType: 'id',
primaryTitle: '编号', primaryTitle: '编号',
action: true, action: true,
searchSpan: 8,
columns: [ columns: [
{ {
title: '组名', title: '组名',

View File

@ -2,6 +2,7 @@
<ContentWrap> <ContentWrap>
<!-- 详情 --> <!-- 详情 -->
<Descriptions :schema="allSchemas.detailSchema" :data="formData" /> <Descriptions :schema="allSchemas.detailSchema" :data="formData" />
<el-button @click="routerReturn" type="primary">返回</el-button>
</ContentWrap> </ContentWrap>
</template> </template>
@ -9,7 +10,8 @@
// import // import
import * as LeaveApi from '@/api/bpm/leave' import * as LeaveApi from '@/api/bpm/leave'
import { allSchemas } from '@/views/bpm/oa/leave/leave.data' import { allSchemas } from '@/views/bpm/oa/leave/leave.data'
import { useRouter } from 'vue-router'
const router = useRouter()
const { query } = useRoute() // const { query } = useRoute() //
const message = useMessage() // const message = useMessage() //
@ -22,6 +24,10 @@ const formData = ref({
reason: undefined reason: undefined
}) })
const routerReturn = () => {
router.back()
}
onMounted(() => { onMounted(() => {
id.value = query.id id.value = query.id
if (!id.value) { if (!id.value) {

View File

@ -16,6 +16,7 @@ const crudSchemas = reactive<VxeCrudSchema>({
primaryTitle: '申请编号', primaryTitle: '申请编号',
action: true, action: true,
actionWidth: '260', actionWidth: '260',
searchSpan: 8,
columns: [ columns: [
{ {
title: t('common.status'), title: t('common.status'),

View File

@ -3,6 +3,10 @@
<!-- 第一步通过流程定义的列表选择对应的流程 --> <!-- 第一步通过流程定义的列表选择对应的流程 -->
<div v-if="!selectProcessInstance"> <div v-if="!selectProcessInstance">
<XTable @register="registerTable"> <XTable @register="registerTable">
<!-- 流程分类 -->
<template #category_default="{ row }">
<DictTag :type="DICT_TYPE.BPM_MODEL_CATEGORY" :value="Number(row?.category)" />
</template>
<template #version_default="{ row }"> <template #version_default="{ row }">
<el-tag v-if="row">v{{ row.version }}</el-tag> <el-tag v-if="row">v{{ row.version }}</el-tag>
</template> </template>
@ -56,6 +60,7 @@ import * as DefinitionApi from '@/api/bpm/definition'
import * as ProcessInstanceApi from '@/api/bpm/processInstance' import * as ProcessInstanceApi from '@/api/bpm/processInstance'
import { setConfAndFields2 } from '@/utils/formCreate' import { setConfAndFields2 } from '@/utils/formCreate'
import { ApiAttrs } from '@form-create/element-ui/types/config' import { ApiAttrs } from '@form-create/element-ui/types/config'
import { DICT_TYPE } from '@/utils/dict'
const router = useRouter() // const router = useRouter() //
const message = useMessage() // const message = useMessage() //

View File

@ -14,7 +14,12 @@ const crudSchemas = reactive<VxeCrudSchema>({
title: '流程分类', title: '流程分类',
field: 'category', field: 'category',
dictType: DICT_TYPE.BPM_MODEL_CATEGORY, dictType: DICT_TYPE.BPM_MODEL_CATEGORY,
dictClass: 'number' dictClass: 'number',
table: {
slots: {
default: 'category_default'
}
}
}, },
{ {
title: '流程版本', title: '流程版本',

View File

@ -7,6 +7,7 @@ const crudSchemas = reactive<VxeCrudSchema>({
primaryKey: 'id', primaryKey: 'id',
primaryType: null, primaryType: null,
action: true, action: true,
searchSpan: 8,
columns: [ columns: [
{ {
title: '任务编号', title: '任务编号',

View File

@ -1,7 +1,7 @@
<template> <template>
<ContentWrap> <ContentWrap>
<!-- 列表 --> <!-- 列表 -->
<XTable @register="registerTable"> <XTable @register="registerTable" ref="xGrid">
<template #options_default="{ row }"> <template #options_default="{ row }">
<span :key="option" v-for="option in row.options"> <span :key="option" v-for="option in row.options">
<el-tag> <el-tag>
@ -145,11 +145,12 @@ import { listSimpleUserGroupsApi } from '@/api/bpm/userGroup'
import { listSimpleDeptApi } from '@/api/system/dept' import { listSimpleDeptApi } from '@/api/system/dept'
import { DICT_TYPE, getDictOptions } from '@/utils/dict' import { DICT_TYPE, getDictOptions } from '@/utils/dict'
import { handleTree, defaultProps } from '@/utils/tree' import { handleTree, defaultProps } from '@/utils/tree'
import { allSchemas, rules } from './taskAssignRule.data' import { allSchemas, rules, idShowActionClick } from './taskAssignRule.data'
const { t } = useI18n() // const { t } = useI18n() //
const message = useMessage() // const message = useMessage() //
const { query } = useRoute() const { query } = useRoute()
const xGrid = ref()
// ========== ========== // ========== ==========
@ -165,6 +166,8 @@ const taskAssignScriptDictDatas = getDictOptions(DICT_TYPE.BPM_TASK_ASSIGN_SCRIP
const modelId = query.modelId const modelId = query.modelId
// processDefinitionId // processDefinitionId
const processDefinitionId = query.processDefinitionId const processDefinitionId = query.processDefinitionId
let isShow = idShowActionClick(modelId)
// //
const queryParams = reactive({ const queryParams = reactive({
modelId: modelId, modelId: modelId,
@ -346,5 +349,10 @@ onMounted(() => {
listSimpleUserGroupsApi().then((data) => { listSimpleUserGroupsApi().then((data) => {
userGroupOptions.value.push(...data) userGroupOptions.value.push(...data)
}) })
if (!isShow) {
setTimeout(() => {
xGrid.value.Ref.hideColumn('actionbtns')
}, 100)
}
}) })
</script> </script>

View File

@ -43,4 +43,12 @@ const crudSchemas = reactive<VxeCrudSchema>({
} }
] ]
}) })
export const idShowActionClick = (modelId?: any) => {
if (modelId) {
return true
} else {
return false
}
}
export const { allSchemas } = useVxeCrudSchemas(crudSchemas) export const { allSchemas } = useVxeCrudSchemas(crudSchemas)

View File

@ -6,7 +6,15 @@ const { t } = useI18n() // 国际化
export const rules = reactive({ export const rules = reactive({
name: [required], name: [required],
sort: [required], sort: [required],
email: [required], // email: [required],
email: [
{ required: true, message: t('profile.rules.mail'), trigger: 'blur' },
{
type: 'email',
message: t('profile.rules.truemail'),
trigger: ['blur', 'change']
}
],
phone: [ phone: [
{ {
len: 11, len: 11,

View File

@ -1,8 +1,18 @@
import type { VxeCrudSchema } from '@/hooks/web/useVxeCrudSchemas' import type { VxeCrudSchema } from '@/hooks/web/useVxeCrudSchemas'
const { t } = useI18n() // 国际化
// 表单校验 // 表单校验
export const rules = reactive({ export const rules = reactive({
mail: [required], // mail: [required],
mail: [
{ required: true, message: t('profile.rules.mail'), trigger: 'blur' },
{
type: 'email',
message: t('profile.rules.truemail'),
trigger: ['blur', 'change']
}
],
username: [required], username: [required],
password: [required], password: [required],
host: [required], host: [required],

View File

@ -131,7 +131,6 @@
ref="treeRef" ref="treeRef"
node-key="id" node-key="id"
show-checkbox show-checkbox
:default-checked-keys="defaultCheckedKeys"
:check-strictly="!checkStrictly" :check-strictly="!checkStrictly"
:props="defaultProps" :props="defaultProps"
:data="treeOptions" :data="treeOptions"
@ -255,7 +254,6 @@ const dialogScopeVisible = ref(false)
const dialogScopeTitle = ref('数据权限') const dialogScopeTitle = ref('数据权限')
const actionScopeType = ref('') const actionScopeType = ref('')
const dataScopeDictDatas = ref() const dataScopeDictDatas = ref()
const defaultCheckedKeys = ref()
// //
const checkStrictly = ref(true) const checkStrictly = ref(true)
const treeNodeAll = ref(false) const treeNodeAll = ref(false)
@ -268,13 +266,16 @@ const handleScope = async (type: string, row: RoleApi.RoleVO) => {
dataScopeForm.id = row.id dataScopeForm.id = row.id
dataScopeForm.name = row.name dataScopeForm.name = row.name
dataScopeForm.code = row.code dataScopeForm.code = row.code
actionScopeType.value = type
dialogScopeVisible.value = true
if (type === 'menu') { if (type === 'menu') {
const menuRes = await listSimpleMenusApi() const menuRes = await listSimpleMenusApi()
treeOptions.value = handleTree(menuRes) treeOptions.value = handleTree(menuRes)
const role = await PermissionApi.listRoleMenusApi(row.id) const role = await PermissionApi.listRoleMenusApi(row.id)
if (role) { if (role) {
// treeRef.value!.setCheckedKeys(role as unknown as Array<number>) role?.forEach((item: any) => {
defaultCheckedKeys.value = role unref(treeRef)?.setChecked(item, true, false)
})
} }
} else if (type === 'data') { } else if (type === 'data') {
const deptRes = await listSimpleDeptApi() const deptRes = await listSimpleDeptApi()
@ -282,12 +283,11 @@ const handleScope = async (type: string, row: RoleApi.RoleVO) => {
const role = await RoleApi.getRoleApi(row.id) const role = await RoleApi.getRoleApi(row.id)
dataScopeForm.dataScope = role.dataScope dataScopeForm.dataScope = role.dataScope
if (role.dataScopeDeptIds) { if (role.dataScopeDeptIds) {
// treeRef.value!.setCheckedKeys(role.dataScopeDeptIds as unknown as Array<number>, false) role.dataScopeDeptIds?.forEach((item: any) => {
defaultCheckedKeys.value = role.dataScopeDeptIds unref(treeRef)?.setChecked(item, true, false)
})
} }
} }
actionScopeType.value = type
dialogScopeVisible.value = true
} }
// //
const submitScope = async () => { const submitScope = async () => {

View File

@ -9,12 +9,19 @@ export const rules = reactive({
}) })
// CrudSchema // CrudSchema
const crudSchemas = reactive<VxeCrudSchema>({ const crudSchemas = reactive<VxeCrudSchema>({
primaryKey: 'id', // primaryKey: 'id',
primaryTitle: '角色编号', // primaryTitle: '角色编号',
primaryType: 'seq', // primaryType: 'seq',
action: true, action: true,
actionWidth: '400px', actionWidth: '400px',
columns: [ columns: [
{
title: '角色编号',
field: 'id',
table: {
width: 200
}
},
{ {
title: '角色名称', title: '角色名称',
field: 'name', field: 'name',

View File

@ -27,6 +27,24 @@ export const rules = reactive({
contactMobile: [required], contactMobile: [required],
accountCount: [required], accountCount: [required],
expireTime: [required], expireTime: [required],
username: [
required,
{
min: 4,
max: 30,
trigger: 'blur',
message: '用户名称长度为 4-30 个字符'
}
],
password: [
required,
{
min: 4,
max: 16,
trigger: 'blur',
message: '密码长度为 4-16 位'
}
],
domain: [required], domain: [required],
status: [required] status: [required]
}) })

View File

@ -135,7 +135,9 @@ const handleUpdate = async (rowId: number) => {
const res = await TenantPackageApi.getTenantPackageApi(rowId) const res = await TenantPackageApi.getTenantPackageApi(rowId)
unref(formRef)?.setValues(res) unref(formRef)?.setValues(res)
// //
unref(treeRef)?.setCheckedKeys(res.menuIds) res.menuIds?.forEach((item: any) => {
unref(treeRef)?.setChecked(item, true, false)
})
} }
// //

View File

@ -332,7 +332,6 @@ const getPostOptions = async () => {
const res = await listSimplePostsApi() const res = await listSimplePostsApi()
postOptions.value.push(...res) postOptions.value.push(...res)
} }
const dataFormater = (val) => { const dataFormater = (val) => {
return deptFormater(deptOptions.value, val) return deptFormater(deptOptions.value, val)
} }
@ -409,15 +408,20 @@ const handleDetail = async (rowId: number) => {
// //
const submitForm = async () => { const submitForm = async () => {
loading.value = true
// //
const elForm = unref(formRef)?.getElFormRef()
if (!elForm) return
elForm.validate(async (valid) => {
if (valid) {
try { try {
const data = unref(formRef)?.formModel as UserApi.UserVO const data = unref(formRef)?.formModel as UserApi.UserVO
if (actionType.value === 'create') { if (actionType.value === 'create') {
await UserApi.createUserApi(data) await UserApi.createUserApi(data)
loading.value = true
message.success(t('common.createSuccess')) message.success(t('common.createSuccess'))
} else { } else {
await UserApi.updateUserApi(data) await UserApi.updateUserApi(data)
loading.value = true
message.success(t('common.updateSuccess')) message.success(t('common.updateSuccess'))
} }
dialogVisible.value = false dialogVisible.value = false
@ -427,6 +431,8 @@ const submitForm = async () => {
await reload() await reload()
loading.value = false loading.value = false
} }
}
})
} }
// //
const handleStatusChange = async (row: UserApi.UserVO) => { const handleStatusChange = async (row: UserApi.UserVO) => {

View File

@ -5,6 +5,8 @@ const { t } = useI18n()
export const rules = reactive({ export const rules = reactive({
username: [required], username: [required],
nickname: [required], nickname: [required],
password: [required],
deptId: [required],
email: [ email: [
{ required: true, message: t('profile.rules.mail'), trigger: 'blur' }, { required: true, message: t('profile.rules.mail'), trigger: 'blur' },
{ {

1
types/global.d.ts vendored
View File

@ -1,4 +1,3 @@
import type { CSSProperties } from 'vue'
declare global { declare global {
declare interface Fn<T = any> { declare interface Fn<T = any> {
(...arg: T[]): T (...arg: T[]): T