hrm前端3版

This commit is contained in:
2025-12-23 10:37:00 +08:00
parent 3c6919013d
commit 56c15ac621
7 changed files with 875 additions and 215 deletions

View File

@@ -0,0 +1,179 @@
<template>
<div class="hrm-page">
<el-card class="metal-panel" shadow="hover">
<div slot="header" class="panel-header">
<span>流程节点配置</span>
<div class="actions-inline">
<el-select v-model="query.tplId" size="mini" placeholder="选择模板" filterable clearable style="width: 200px" @change="loadList">
<el-option v-for="tpl in templateOptions" :key="tpl.tplId" :label="`${tpl.tplName || tpl.tplCode} (${tpl.bizType || ''})`" :value="tpl.tplId" />
</el-select>
<el-input v-model="query.nodeType" size="mini" placeholder="节点类型" clearable style="width: 140px" @keyup.enter.native="loadList" />
<el-button size="mini" type="primary" icon="el-icon-plus" @click="openDialog()">新增</el-button>
<el-button size="mini" icon="el-icon-refresh" @click="loadList">刷新</el-button>
</div>
</div>
<el-table :data="list" v-loading="loading" height="520" stripe>
<el-table-column label="序号" prop="orderNo" width="80" />
<el-table-column label="节点类型" prop="nodeType" min-width="140" />
<el-table-column label="审批规则" prop="approverRule" min-width="160" />
<el-table-column label="规则值" prop="approverValue" min-width="200" show-overflow-tooltip />
<el-table-column label="备注" prop="remark" min-width="200" show-overflow-tooltip />
<el-table-column label="操作" width="180" fixed="right">
<template slot-scope="scope">
<el-button size="mini" type="text" @click="openDialog(scope.row)">编辑</el-button>
<el-button size="mini" type="text" @click="delRow(scope.row)">删除</el-button>
</template>
</el-table-column>
</el-table>
</el-card>
<el-dialog :visible.sync="dialogVisible" title="流程节点" width="520px" append-to-body>
<el-form ref="formRef" :model="form" :rules="rules" label-width="110px" size="small">
<el-form-item label="模板" prop="tplId">
<el-select v-model="form.tplId" placeholder="选择模板" filterable style="width: 100%">
<el-option v-for="tpl in templateOptions" :key="tpl.tplId" :label="`${tpl.tplName || tpl.tplCode} (${tpl.bizType || ''})`" :value="tpl.tplId" />
</el-select>
</el-form-item>
<el-form-item label="顺序" prop="orderNo">
<el-input-number v-model="form.orderNo" :min="1" :step="1" controls-position="right" />
</el-form-item>
<el-form-item label="节点类型" prop="nodeType">
<el-input v-model="form.nodeType" placeholder="如 approve/cc/end" />
</el-form-item>
<el-form-item label="审批规则" prop="approverRule">
<el-select v-model="form.approverRule" placeholder="选择规则" style="width: 100%">
<el-option v-for="opt in approverRuleOptions" :key="opt.value" :label="opt.label" :value="opt.value" />
</el-select>
</el-form-item>
<el-form-item label="规则值" prop="approverValue">
<el-input v-model="form.approverValue" placeholder="根据规则填写用户ID/角色编码/岗位ID/字段名等" />
<div class="muted">fixed_user: 用户ID逗号分隔role: 角色编码position: 岗位IDleader/initiator 无需填form_field: 表单字段名</div>
</el-form-item>
<el-form-item label="备注">
<el-input v-model="form.remark" type="textarea" :rows="2" />
</el-form-item>
</el-form>
<div slot="footer">
<el-button @click="dialogVisible = false">取消</el-button>
<el-button type="primary" :loading="submitting" @click="submit">保存</el-button>
</div>
</el-dialog>
</div>
</template>
<script>
import { listFlowNode, addFlowNode, updateFlowNode, delFlowNode, listFlowTemplate } from '@/api/hrm'
export default {
name: 'HrmFlowNode',
data() {
return {
list: [],
loading: false,
query: { tplId: undefined, nodeType: '' },
templateOptions: [],
dialogVisible: false,
submitting: false,
form: {},
approverRuleOptions: [
{ label: '固定用户', value: 'fixed_user' },
{ label: '角色', value: 'role' },
{ label: '岗位', value: 'position' },
{ label: '直属上级', value: 'leader' },
{ label: '发起人', value: 'initiator' },
{ label: '表单字段指定', value: 'form_field' }
],
rules: {
tplId: [{ required: true, message: '请选择模板', trigger: 'change' }],
orderNo: [{ required: true, message: '请输入顺序', trigger: 'blur' }],
nodeType: [{ required: true, message: '请输入节点类型', trigger: 'blur' }],
approverRule: [{ required: true, message: '请选择审批规则', trigger: 'change' }]
}
}
},
created() {
this.loadTemplates()
this.loadList()
},
methods: {
loadTemplates() {
listFlowTemplate({ pageNum: 1, pageSize: 200 })
.then(res => {
this.templateOptions = res.rows || []
})
},
loadList() {
this.loading = true
listFlowNode({ pageNum: 1, pageSize: 500, ...this.query })
.then(res => {
this.list = res.rows || []
})
.finally(() => {
this.loading = false
})
},
openDialog(row) {
this.form = row
? { ...row }
: {
tplId: this.query.tplId || (this.templateOptions[0] && this.templateOptions[0].tplId),
orderNo: (this.list[this.list.length - 1]?.orderNo || 0) + 1,
nodeType: '',
approverRule: '',
approverValue: '',
remark: ''
}
this.dialogVisible = true
this.$nextTick(() => this.$refs.formRef && this.$refs.formRef.clearValidate())
},
submit() {
this.$refs.formRef.validate(valid => {
if (!valid) return
this.submitting = true
const api = this.form.nodeId ? updateFlowNode : addFlowNode
api(this.form)
.then(() => {
this.$message.success('已保存')
this.dialogVisible = false
this.loadList()
})
.finally(() => {
this.submitting = false
})
})
},
delRow(row) {
this.$confirm('确认删除该节点吗?', '提示', { type: 'warning' }).then(() => {
delFlowNode(row.nodeId).then(() => {
this.$message.success('已删除')
this.loadList()
})
})
}
}
}
</script>
<style scoped lang="scss">
.hrm-page {
padding: 16px 20px 32px;
background: #f8f9fb;
}
.panel-header {
display: flex;
justify-content: space-between;
align-items: center;
font-weight: 600;
color: #303133;
}
.actions-inline {
display: flex;
gap: 8px;
align-items: center;
}
.muted {
color: #909399;
font-size: 12px;
margin-top: 4px;
}
</style>

View File

@@ -0,0 +1,161 @@
<template>
<div class="hrm-page">
<el-card class="metal-panel" shadow="hover">
<div slot="header" class="panel-header">
<span>流程模板</span>
<div class="actions-inline">
<el-input v-model="query.tplName" size="mini" placeholder="模板名称" clearable style="width: 160px" @keyup.enter.native="loadList" />
<el-select v-model="query.bizType" size="mini" placeholder="业务类型" clearable style="width: 140px" @change="loadList">
<el-option label="请假" value="leave" />
<el-option label="加班" value="overtime" />
<el-option label="出差" value="travel" />
<el-option label="用印" value="seal" />
<el-option label="薪酬" value="payroll" />
</el-select>
<el-button size="mini" type="primary" icon="el-icon-plus" @click="openDialog()">新增</el-button>
<el-button size="mini" icon="el-icon-refresh" @click="loadList">刷新</el-button>
</div>
</div>
<el-table :data="list" v-loading="loading" height="520" stripe>
<el-table-column label="名称" prop="tplName" min-width="160" />
<el-table-column label="编码" prop="tplCode" min-width="140" />
<el-table-column label="业务类型" prop="bizType" min-width="120" />
<el-table-column label="版本" prop="version" width="90" />
<el-table-column label="启用" prop="enabled" width="90">
<template slot-scope="scope">
<el-tag :type="scope.row.enabled ? 'success' : 'info'" size="mini">{{ scope.row.enabled ? '启用' : '停用' }}</el-tag>
</template>
</el-table-column>
<el-table-column label="备注" prop="remark" min-width="200" show-overflow-tooltip />
<el-table-column label="操作" width="180" fixed="right">
<template slot-scope="scope">
<el-button size="mini" type="text" @click="openDialog(scope.row)">编辑</el-button>
<el-button size="mini" type="text" @click="delRow(scope.row)">删除</el-button>
</template>
</el-table-column>
</el-table>
</el-card>
<el-dialog :visible.sync="dialogVisible" title="流程模板" width="480px" append-to-body>
<el-form ref="formRef" :model="form" :rules="rules" label-width="100px" size="small">
<el-form-item label="模板名称" prop="tplName">
<el-input v-model="form.tplName" />
</el-form-item>
<el-form-item label="模板编码" prop="tplCode">
<el-input v-model="form.tplCode" />
</el-form-item>
<el-form-item label="业务类型" prop="bizType">
<el-select v-model="form.bizType" placeholder="选择业务" style="width: 100%">
<el-option label="请假" value="leave" />
<el-option label="加班" value="overtime" />
<el-option label="出差" value="travel" />
<el-option label="用印" value="seal" />
<el-option label="薪酬" value="payroll" />
</el-select>
</el-form-item>
<el-form-item label="版本" prop="version">
<el-input-number v-model="form.version" :min="1" :step="1" controls-position="right" />
</el-form-item>
<el-form-item label="启用" prop="enabled">
<el-switch v-model="form.enabled" :active-value="1" :inactive-value="0" />
</el-form-item>
<el-form-item label="备注">
<el-input v-model="form.remark" type="textarea" :rows="2" />
</el-form-item>
</el-form>
<div slot="footer">
<el-button @click="dialogVisible = false">取消</el-button>
<el-button type="primary" :loading="submitting" @click="submit">保存</el-button>
</div>
</el-dialog>
</div>
</template>
<script>
import { listFlowTemplate, addFlowTemplate, updateFlowTemplate, delFlowTemplate } from '@/api/hrm'
export default {
name: 'HrmFlowTemplate',
data() {
return {
list: [],
loading: false,
query: { tplName: '', bizType: undefined },
dialogVisible: false,
submitting: false,
form: {},
rules: {
tplName: [{ required: true, message: '请输入模板名称', trigger: 'blur' }],
tplCode: [{ required: true, message: '请输入模板编码', trigger: 'blur' }],
bizType: [{ required: true, message: '请选择业务类型', trigger: 'change' }],
version: [{ required: true, message: '请输入版本号', trigger: 'blur' }]
}
}
},
created() {
this.loadList()
},
methods: {
loadList() {
this.loading = true
listFlowTemplate({ pageNum: 1, pageSize: 200, ...this.query })
.then(res => {
this.list = res.rows || []
})
.finally(() => {
this.loading = false
})
},
openDialog(row) {
this.form = row
? { ...row }
: { tplName: '', tplCode: '', bizType: '', version: 1, enabled: 1, remark: '' }
this.dialogVisible = true
this.$nextTick(() => this.$refs.formRef && this.$refs.formRef.clearValidate())
},
submit() {
this.$refs.formRef.validate(valid => {
if (!valid) return
this.submitting = true
const api = this.form.tplId ? updateFlowTemplate : addFlowTemplate
api(this.form)
.then(() => {
this.$message.success('已保存')
this.dialogVisible = false
this.loadList()
})
.finally(() => {
this.submitting = false
})
})
},
delRow(row) {
this.$confirm('确认删除该模板吗?', '提示', { type: 'warning' }).then(() => {
delFlowTemplate(row.tplId).then(() => {
this.$message.success('已删除')
this.loadList()
})
})
}
}
}
</script>
<style scoped lang="scss">
.hrm-page {
padding: 16px 20px 32px;
background: #f8f9fb;
}
.panel-header {
display: flex;
justify-content: space-between;
align-items: center;
font-weight: 600;
color: #303133;
}
.actions-inline {
display: flex;
gap: 8px;
align-items: center;
}
</style>