..
This commit is contained in:
@@ -102,143 +102,6 @@
|
||||
background-color: hsla(0, 0%, 60%, 0.05);
|
||||
}
|
||||
|
||||
.ele-setting-wrapper {
|
||||
padding: 20px 18px;
|
||||
}
|
||||
|
||||
.ele-setting-wrapper .ele-setting-title {
|
||||
font-size: 13px;
|
||||
margin-bottom: 15px;
|
||||
}
|
||||
|
||||
.ele-setting-wrapper .ele-setting-theme > div {
|
||||
width: 52px;
|
||||
height: 36px;
|
||||
line-height: 1;
|
||||
font-size: 18px;
|
||||
border-radius: 3px;
|
||||
margin: 0 20px 30px 0;
|
||||
padding: 14px 0 0 24px;
|
||||
-webkit-box-sizing: border-box;
|
||||
box-sizing: border-box;
|
||||
-webkit-box-shadow: 0 1px 4px rgba(0, 0, 0, 0.15);
|
||||
box-shadow: 0 1px 4px rgba(0, 0, 0, 0.15);
|
||||
display: inline-block;
|
||||
vertical-align: top;
|
||||
position: relative;
|
||||
overflow: hidden;
|
||||
cursor: pointer;
|
||||
-webkit-transition: background-color 0.2s;
|
||||
transition: background-color 0.2s;
|
||||
}
|
||||
|
||||
.ele-setting-wrapper .ele-setting-theme > div:after,
|
||||
.ele-setting-wrapper .ele-setting-theme > div:before,
|
||||
.ele-setting-wrapper .ele-setting-theme > div > .ele-bg-primary {
|
||||
content: "";
|
||||
width: 100%;
|
||||
height: 10px;
|
||||
background: #fff;
|
||||
position: absolute;
|
||||
left: 0;
|
||||
top: 0;
|
||||
-webkit-transition: background-color 0.2s;
|
||||
transition: background-color 0.2s;
|
||||
}
|
||||
|
||||
.ele-setting-wrapper .ele-setting-theme > div:after {
|
||||
width: 14px;
|
||||
height: 100%;
|
||||
}
|
||||
|
||||
.ele-setting-wrapper .ele-setting-theme > div.ele-head-dark:before,
|
||||
.ele-setting-wrapper .ele-setting-theme > div.ele-layout-mix:after,
|
||||
.ele-setting-wrapper .ele-setting-theme > div.ele-layout-mix:before,
|
||||
.ele-setting-wrapper .ele-setting-theme > div.ele-side-dark:after {
|
||||
background: #001529;
|
||||
}
|
||||
|
||||
.ele-setting-wrapper .ele-setting-theme > div.ele-head-dark:before,
|
||||
.ele-setting-wrapper .ele-setting-theme > div.ele-head-light:before,
|
||||
.ele-setting-wrapper .ele-setting-theme > div > .ele-bg-primary {
|
||||
z-index: 1;
|
||||
}
|
||||
|
||||
.ele-setting-wrapper .ele-setting-theme > div.ele-layout-top {
|
||||
padding-left: 19px;
|
||||
}
|
||||
|
||||
.ele-setting-wrapper .ele-setting-theme > div.ele-layout-top:after {
|
||||
display: none;
|
||||
}
|
||||
|
||||
.ele-setting-wrapper .ele-setting-colors {
|
||||
color: #fff;
|
||||
margin-bottom: 20px;
|
||||
}
|
||||
|
||||
.ele-setting-wrapper .ele-setting-colors .ele-setting-color-item {
|
||||
width: 20px;
|
||||
height: 20px;
|
||||
line-height: 22px;
|
||||
border-radius: 2px;
|
||||
margin: 8px 8px 0 0;
|
||||
display: inline-block;
|
||||
-webkit-box-shadow: 0 1px 4px rgba(0, 0, 0, 0.15);
|
||||
box-shadow: 0 1px 4px rgba(0, 0, 0, 0.15);
|
||||
vertical-align: top;
|
||||
position: relative;
|
||||
text-align: center;
|
||||
cursor: pointer;
|
||||
}
|
||||
|
||||
.ele-setting-wrapper .ele-setting-item {
|
||||
display: -webkit-box;
|
||||
display: -ms-flexbox;
|
||||
display: flex;
|
||||
-webkit-box-align: center;
|
||||
-ms-flex-align: center;
|
||||
align-items: center;
|
||||
margin-bottom: 20px;
|
||||
}
|
||||
|
||||
.ele-setting-wrapper .ele-setting-item .setting-item-title {
|
||||
-webkit-box-flex: 1;
|
||||
-ms-flex: 1;
|
||||
flex: 1;
|
||||
line-height: 28px;
|
||||
}
|
||||
|
||||
.ele-setting-wrapper .ele-setting-item .setting-item-control {
|
||||
line-height: 1;
|
||||
}
|
||||
|
||||
.ele-setting-wrapper .el-divider {
|
||||
margin-bottom: 20px;
|
||||
}
|
||||
|
||||
.ele-setting-wrapper .el-alert + .ele-setting-button-group {
|
||||
margin-top: 15px;
|
||||
}
|
||||
|
||||
.ele-setting-dark .ele-setting-theme > div {
|
||||
-webkit-box-shadow: 0 1px 4px rgba(0, 0, 0, 0.55);
|
||||
box-shadow: 0 1px 4px rgba(0, 0, 0, 0.55);
|
||||
}
|
||||
|
||||
.ele-setting-dark .ele-setting-theme > div:after,
|
||||
.ele-setting-dark .ele-setting-theme > div:before,
|
||||
.ele-setting-dark .ele-setting-theme > div > .ele-bg-primary {
|
||||
background: #1f1f1f;
|
||||
}
|
||||
|
||||
.ele-setting-dark .ele-setting-theme > div.ele-head-dark:before,
|
||||
.ele-setting-dark .ele-setting-theme > div.ele-layout-mix:after,
|
||||
.ele-setting-dark .ele-setting-theme > div.ele-layout-mix:before,
|
||||
.ele-setting-dark .ele-setting-theme > div.ele-side-dark:after {
|
||||
background: #262626;
|
||||
}
|
||||
|
||||
.ele-setting-color-picker.el-color-picker {
|
||||
height: auto;
|
||||
margin-top: 8px;
|
||||
@@ -318,66 +181,6 @@
|
||||
right: 20px;
|
||||
}
|
||||
|
||||
.ele-admin-collapse .ele-admin-sidebar-menus > .el-scrollbar > .el-scrollbar__wrap > .el-scrollbar__view > .el-menu > .el-menu-item .ele-menu-badge,
|
||||
.ele-admin-collapse
|
||||
.ele-admin-sidebar-menus
|
||||
> .el-scrollbar
|
||||
> .el-scrollbar__wrap
|
||||
> .el-scrollbar__view
|
||||
> .el-menu
|
||||
> .el-submenu
|
||||
> .el-submenu__title
|
||||
.ele-menu-badge {
|
||||
top: 2px;
|
||||
right: 2px;
|
||||
margin: 0;
|
||||
}
|
||||
|
||||
.ele-admin-header-nav > .el-scrollbar > .el-scrollbar__wrap > .el-scrollbar__view > .el-menu > .el-menu-item .ele-menu-badge,
|
||||
.ele-admin-header-nav > .el-scrollbar > .el-scrollbar__wrap > .el-scrollbar__view > .el-menu > .el-submenu > .el-submenu__title .ele-menu-badge {
|
||||
position: static;
|
||||
right: auto;
|
||||
top: auto;
|
||||
display: inline-block;
|
||||
vertical-align: 6px;
|
||||
margin: 0 0 0 2px;
|
||||
}
|
||||
|
||||
.ele-admin-sidebar-nav-menu > .el-scrollbar > .el-scrollbar__wrap > .el-scrollbar__view > .el-menu > .el-menu-item .ele-menu-badge,
|
||||
.ele-admin-sidebar-nav-menu
|
||||
> .el-scrollbar
|
||||
> .el-scrollbar__wrap
|
||||
> .el-scrollbar__view
|
||||
> .el-menu
|
||||
> .el-submenu
|
||||
> .el-submenu__title
|
||||
.ele-menu-badge {
|
||||
top: 0;
|
||||
right: 0;
|
||||
margin: 0;
|
||||
}
|
||||
|
||||
.ele-admin-nav-collapse
|
||||
.ele-admin-sidebar-nav-menu
|
||||
> .el-scrollbar
|
||||
> .el-scrollbar__wrap
|
||||
> .el-scrollbar__view
|
||||
> .el-menu
|
||||
> .el-menu-item
|
||||
.ele-menu-badge,
|
||||
.ele-admin-nav-collapse
|
||||
.ele-admin-sidebar-nav-menu
|
||||
> .el-scrollbar
|
||||
> .el-scrollbar__wrap
|
||||
> .el-scrollbar__view
|
||||
> .el-menu
|
||||
> .el-submenu
|
||||
> .el-submenu__title
|
||||
.ele-menu-badge {
|
||||
top: 0;
|
||||
right: 0;
|
||||
}
|
||||
|
||||
@media only screen and (max-width: 767px) {
|
||||
.hidden-xs-only {
|
||||
display: none !important;
|
||||
@@ -24318,18 +24121,6 @@ s:not([class]) {
|
||||
flex-wrap: wrap;
|
||||
}
|
||||
|
||||
.ele-body {
|
||||
padding: 15px;
|
||||
}
|
||||
|
||||
.ele-body.ele-body-card {
|
||||
padding-bottom: 0;
|
||||
}
|
||||
|
||||
.ele-body.ele-body-card .el-card {
|
||||
margin-bottom: 15px;
|
||||
}
|
||||
|
||||
.ele-bottom-tool {
|
||||
position: fixed;
|
||||
bottom: 0;
|
||||
|
||||
@@ -648,46 +648,76 @@ td.no-b {
|
||||
width: auto;
|
||||
}
|
||||
|
||||
.form-box{
|
||||
.form-box {
|
||||
width: 1200px;
|
||||
margin: 0 auto;
|
||||
}
|
||||
|
||||
.descriptions-form .el-form-item {
|
||||
margin-bottom: 0 !important;
|
||||
}
|
||||
/**********start****************设置工作流表单el-description嵌套el-form的格式 必须要使用flow-task-form!!!***********************start*****************/
|
||||
|
||||
.el-descriptions__table {
|
||||
.flow-task-form .el-descriptions__table {
|
||||
table-layout: fixed !important;
|
||||
}
|
||||
|
||||
.el-descriptions-item__label {
|
||||
text-align: center !important;
|
||||
width: 14% !important;
|
||||
}
|
||||
|
||||
.descriptions-form th.el-descriptions-item__label:has(+ td.el-descriptions-item__content > div.el-form-item.is-required):before {
|
||||
content: "*";
|
||||
color: #f56c6c;
|
||||
margin-right: 3px;
|
||||
}
|
||||
|
||||
.descriptions-form .el-form-item .el-form-item__label {
|
||||
.flow-task-form .el-form-item .el-form-item__label {
|
||||
display: none;
|
||||
}
|
||||
|
||||
.descriptions-form .el-form-item .el-form-item__content > div {
|
||||
width: 100%;
|
||||
.flow-task-form .el-descriptions-item__label.is-bordered-label {
|
||||
color: rgb(102, 102, 102) !important;
|
||||
font-weight: bold !important;
|
||||
background: rgb(248, 249, 250) !important;
|
||||
padding: 8px 12px !important;
|
||||
border: 1px solid rgb(221, 221, 221) !important;
|
||||
text-align: center !important;
|
||||
}
|
||||
|
||||
.flow-task-form .el-descriptions .is-bordered .el-descriptions-item__cell {
|
||||
border: 1px solid rgb(221, 221, 221) !important;
|
||||
}
|
||||
|
||||
.flow-task-form .el-descriptions-item__content {
|
||||
font-weight: 600;
|
||||
}
|
||||
|
||||
|
||||
.descriptions-form .el-form-item input, .descriptions-form .el-form-item textarea {
|
||||
.flow-task-form .el-form-item .el-form-item__content > div {
|
||||
width: 100%;
|
||||
}
|
||||
|
||||
.flow-task-form .el-descriptions-item__cell.el-descriptions-item__content .el-form-item {
|
||||
margin-bottom: 0 !important;
|
||||
}
|
||||
|
||||
/**********start****************设置工作流表单el-description嵌套el-form的格式 必填项加星号***********************start*****************/
|
||||
.flow-task-form th.el-descriptions-item__label:has(+ td.el-descriptions-item__content > div.el-form-item.is-required):before {
|
||||
content: "*";
|
||||
color: #ff0202;
|
||||
margin-right: 3px;
|
||||
}
|
||||
|
||||
/**/
|
||||
|
||||
.flow-task-form .el-form-item input, .flow-task-form .el-form-item textarea, .flow-task-form .el-form-item .el-radio.is-bordered {
|
||||
/*border: none;*/
|
||||
border-radius: unset;
|
||||
border: 1px solid rgb(221, 221, 221);
|
||||
}
|
||||
|
||||
.descriptions-form .el-form-item .el-date-editor {
|
||||
.flow-task-form .el-form-item .el-radio.is-bordered {
|
||||
border: 1px solid rgb(221, 221, 221);
|
||||
}
|
||||
|
||||
.flow-task-form .el-form-item .el-radio.is-bordered.is-checked {
|
||||
border-color: var(--color-primary);
|
||||
}
|
||||
|
||||
|
||||
.flow-task-form .el-form-item .el-date-editor {
|
||||
width: 100%;
|
||||
}
|
||||
|
||||
|
||||
/*********END********设置工作流表单el-description嵌套el-form的格式**************************END*********/
|
||||
|
||||
|
||||
|
||||
@@ -0,0 +1,138 @@
|
||||
:root {
|
||||
--color-primary: #006db9; /* 主色 */
|
||||
--color-primary-1: #e6f3ff; /* 最浅,用于浅色背景 */
|
||||
--color-primary-2: #b3d9ff; /* 较浅,用于 hover/light-bg */
|
||||
--color-primary-3: #80c0ff; /* 轻微强调 */
|
||||
--color-primary-4: #4da6ff; /* 中等强调 */
|
||||
--color-primary-5: #1a8cff; /* 较强强调 */
|
||||
--color-primary-6: #006db9; /* 主色(默认) */
|
||||
--color-primary-7: #005aa3; /* 点击/active 状态 */
|
||||
--color-primary-8: #00468c; /* 较深,用于文字/强调 */
|
||||
--color-primary-9: #003370; /* 更深,用于深色模式 */
|
||||
--color-primary-10: #002054; /* 最深,用于特殊强调 */
|
||||
|
||||
--color-success: #52c41a;
|
||||
--color-success-1: #f6ffed;
|
||||
--color-success-2: #d9f7be;
|
||||
--color-success-3: #b7eb8f;
|
||||
--color-success-4: #95de64;
|
||||
--color-success-5: #73d13d;
|
||||
--color-success-6: #52c41a;
|
||||
--color-success-7: #389e0d;
|
||||
--color-success-8: #237804;
|
||||
--color-success-9: #135200;
|
||||
--color-success-10: #092b00;
|
||||
--color-warning: #faad14;
|
||||
--color-warning-1: #fffbe6;
|
||||
--color-warning-2: #fff1b8;
|
||||
--color-warning-3: #ffe58f;
|
||||
--color-warning-4: #ffd666;
|
||||
--color-warning-5: #ffc53d;
|
||||
--color-warning-6: #faad14;
|
||||
--color-warning-7: #d48806;
|
||||
--color-warning-8: #ad6800;
|
||||
--color-warning-9: #874d00;
|
||||
--color-warning-10: #613400;
|
||||
--color-danger: #ff4d4f;
|
||||
--color-danger-1: #fff1f0;
|
||||
--color-danger-2: #ffccc7;
|
||||
--color-danger-3: #ffa39e;
|
||||
--color-danger-4: #ff7875;
|
||||
--color-danger-5: #ff4d4f;
|
||||
--color-danger-6: #f5222d;
|
||||
--color-danger-7: #cf1322;
|
||||
--color-danger-8: #a8071a;
|
||||
--color-danger-9: #820014;
|
||||
--color-danger-10: #5c0011;
|
||||
--color-info: #909399;
|
||||
--color-info-1: #f4f4f5;
|
||||
--color-info-2: #dedfe0;
|
||||
--color-info-3: #d3d4d6;
|
||||
--color-info-4: #bcbec2;
|
||||
--color-info-5: #a6a9ad;
|
||||
--color-info-6: #909399;
|
||||
--color-info-7: #6e7074;
|
||||
--color-info-8: #58595c;
|
||||
--color-info-9: #414244;
|
||||
--color-info-10: #2a2b2b;
|
||||
--color-white: #fff;
|
||||
--color-white-5: hsla(0, 0%, 100%, 0.5);
|
||||
--color-black: #000;
|
||||
--color-black-1: rgba(0, 0, 0, 0.1);
|
||||
--color-black-3: rgba(0, 0, 0, 0.3);
|
||||
--color-black-5: rgba(0, 0, 0, 0.5);
|
||||
--color-text-primary: #303133;
|
||||
--color-text-regular: #606266;
|
||||
--color-text-secondary: #909399;
|
||||
--color-text-placeholder: #c0c4cc;
|
||||
--color-text-dark-primary: #fff;
|
||||
--color-text-dark-regular: hsla(0, 0%, 100%, 0.8);
|
||||
--border-color-base: #ddd;
|
||||
--border-color-light: #e5e5e5;
|
||||
--border-color-lighter: #ededed;
|
||||
--border-color-extra-light: #f4f4f4;
|
||||
--background-color-base: #fafafa;
|
||||
--box-shadow-base: 0 2px 4px rgba(0, 0, 0, 0.12), 0 0 6px rgba(0, 0, 0, 0.04);
|
||||
--box-shadow-dark: 0 2px 4px rgba(0, 0, 0, 0.12), 0 0 6px rgba(0, 0, 0, 0.12);
|
||||
--box-shadow-light: 0 4px 12px 0 rgba(0, 0, 0, 0.15);
|
||||
--checkbox-background-color: var(--color-white);
|
||||
--radio-input-background-color: var(--color-white);
|
||||
--radio-checked-icon-color: var(--color-white);
|
||||
--input-background-color: var(--color-white);
|
||||
--button-default-background-color: var(--color-white);
|
||||
--button-disabled-background-color: var(--color-white);
|
||||
--button-default-border-color-5: hsla(0, 0%, 87%, 0.5);
|
||||
--table-header-background-color: var(--background-color-base);
|
||||
--table-fixed-box-shadow: 0 0 10px rgba(0, 0, 0, 0.12);
|
||||
--popup-modal-background-color: #000;
|
||||
--popup-modal-opacity: 0.5;
|
||||
--popover-background-color: var(--color-white);
|
||||
--dialog-box-shadow: 0 1px 3px rgba(0, 0, 0, 0.3);
|
||||
--tooltip-fill: var(--color-text-primary);
|
||||
--tooltip-color: var(--color-text-dark-primary);
|
||||
--tooltip-border-color: var(--tooltip-fill);
|
||||
--scrollbar-background-color: hsla(0, 0%, 67%, 0.5);
|
||||
--scrollbar-hover-background-color: hsla(0, 0%, 67%, 0.8);
|
||||
--backtop-background-color: var(--color-white);
|
||||
--backtop-font-color: var(--color-primary);
|
||||
--backtop-hover-background-color: var(--border-color-extra-light);
|
||||
--avatar-background-color: #c0c4cc;
|
||||
--skeleton-color: #f2f2f2;
|
||||
--skeleton-to-color: #e6e6e6;
|
||||
--svg-monochrome-grey: #dcdde0;
|
||||
--loading-mask-bg: hsla(0, 0%, 100%, 0.9);
|
||||
--menu-dark-background: #191a23;
|
||||
--layout-body-background: #f0f2f5;
|
||||
--sidebar-background-light: var(--color-white);
|
||||
--sidebar-background-dark: var(--menu-dark-background);
|
||||
--sidebar-light-shadow: 1px 3px 3px rgba(0, 21, 41, 0.08);
|
||||
--sidebar-dark-shadow: 0 4px 4px rgba(0, 0, 0, 0.35);
|
||||
--header-background: var(--menu-dark-background);
|
||||
--header-light-background: var(--color-white);
|
||||
--header-light-shadow: 0 1px 4px rgba(0, 21, 41, 0.08);
|
||||
--header-dark-shadow: 0 1px 4px rgba(0, 0, 0, 0.1);
|
||||
--header-tool-hover-bg: rgba(0, 0, 0, 0.025);
|
||||
--header-dark-tool-hover-bg: hsla(0, 0%, 100%, 0.05);
|
||||
--logo-light-shadow: 1px 2px 3px rgba(0, 21, 41, 0.08);
|
||||
--logo-dark-shadow: 0 3px 4px rgba(0, 0, 0, 0.35);
|
||||
--content-image-filter: none;
|
||||
--el-mask-color: rgba(255, 255, 255, 0.4);
|
||||
--el-mask-color-extra-light: rgba(255, 255, 255, 0.6);
|
||||
}
|
||||
|
||||
* {
|
||||
box-sizing: border-box;
|
||||
margin: 0;
|
||||
padding: 0;
|
||||
}
|
||||
|
||||
html,
|
||||
body {
|
||||
padding: 0;
|
||||
margin: 0;
|
||||
font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, Oxygen, Ubuntu, Cantarell, sans-serif;
|
||||
background-color: #f5f7fa;
|
||||
color: #333;
|
||||
font-size: 14px;
|
||||
height: 100%;
|
||||
}
|
||||
@@ -38,32 +38,32 @@ $.ajaxSetup({
|
||||
})
|
||||
|
||||
//初始化pjax
|
||||
;(function initPjax() {
|
||||
if ($.support.pjax) {
|
||||
$(document).pjax("a[data-pjax]", "#container", {
|
||||
maxCacheLength: 0,
|
||||
push: false,
|
||||
replace: true,
|
||||
fragment: "#container",
|
||||
timeout: 8000
|
||||
})
|
||||
$(document).on("pjax:send", function () {
|
||||
NProgress.start()
|
||||
$(".ele-admin-content-view").hide()
|
||||
window.customStyleList = document.querySelectorAll('style[id^="style-"]')
|
||||
})
|
||||
|
||||
$(document).on("pjax:complete", function () {
|
||||
if (window.customStyleList) {
|
||||
window.customStyleList.forEach((style) => {
|
||||
style.parentNode.removeChild(style)
|
||||
})
|
||||
}
|
||||
NProgress.done()
|
||||
$(".ele-admin-content-view").show()
|
||||
})
|
||||
}
|
||||
})()
|
||||
// ;(function initPjax() {
|
||||
// if ($.support.pjax) {
|
||||
// $(document).pjax("a[data-pjax]", "#container", {
|
||||
// maxCacheLength: 0,
|
||||
// push: false,
|
||||
// replace: true,
|
||||
// fragment: "#container",
|
||||
// timeout: 8000
|
||||
// })
|
||||
// $(document).on("pjax:send", function () {
|
||||
// NProgress.start()
|
||||
// $(".ele-admin-content-view").hide()
|
||||
// window.customStyleList = document.querySelectorAll('style[id^="style-"]')
|
||||
// })
|
||||
//
|
||||
// $(document).on("pjax:complete", function () {
|
||||
// if (window.customStyleList) {
|
||||
// window.customStyleList.forEach((style) => {
|
||||
// style.parentNode.removeChild(style)
|
||||
// })
|
||||
// }
|
||||
// NProgress.done()
|
||||
// $(".ele-admin-content-view").show()
|
||||
// })
|
||||
// }
|
||||
// })()
|
||||
|
||||
function pjaxReplace(url, data = {}) {
|
||||
const { pathname, search } = location
|
||||
|
||||
@@ -17,7 +17,7 @@ const commonUtil = {
|
||||
if (response.config.responseType === "blob") {
|
||||
return response
|
||||
}
|
||||
if (response.data && response.data.code !== 0) {
|
||||
if (response.data && response.data.code !== 0 && response.data.code !== 200) {
|
||||
if (isMobile) {
|
||||
vant.Toast(response.data.msg)
|
||||
} else {
|
||||
@@ -25,7 +25,7 @@ const commonUtil = {
|
||||
}
|
||||
return Promise.reject(response.data)
|
||||
}
|
||||
return response.data
|
||||
return response.data || response.result
|
||||
},
|
||||
(error) => {
|
||||
const userAgent = navigator.userAgent || navigator.vendor || window.opera
|
||||
@@ -217,6 +217,7 @@ const commonUtil = {
|
||||
function doSm2Encrypt(msgString) {
|
||||
return sm2.doEncrypt(msgString, publicKey, cipherMode)
|
||||
}
|
||||
|
||||
// SM2数组加密
|
||||
function doSm2ArrayEncrypt(msgString) {
|
||||
return sm2.doEncrypt(msgString, publicKey, cipherMode)
|
||||
|
||||
+7
-7
@@ -1450,7 +1450,7 @@
|
||||
.el-dropdown-menu__item:focus,
|
||||
.el-dropdown-menu__item:not(.is-disabled):hover {
|
||||
background-color: #ecf5ff;
|
||||
color: #66b1ff;
|
||||
color: var(--color-primary-6);
|
||||
}
|
||||
.el-dropdown-menu__item i {
|
||||
margin-right: 5px;
|
||||
@@ -2768,7 +2768,7 @@
|
||||
}
|
||||
.el-table-filter__list-item:hover {
|
||||
background-color: #ecf5ff;
|
||||
color: #66b1ff;
|
||||
color: var(--color-primary-6);
|
||||
}
|
||||
.el-table-filter__list-item.is-active {
|
||||
background-color: var(--color-primary);
|
||||
@@ -9789,7 +9789,7 @@
|
||||
}
|
||||
.el-tag--dark .el-tag__close:hover {
|
||||
color: #fff;
|
||||
background-color: #66b1ff;
|
||||
background-color: var(--color-primary-6);
|
||||
}
|
||||
.el-tag--dark.el-tag--info {
|
||||
background-color: #909399;
|
||||
@@ -10963,8 +10963,8 @@
|
||||
}
|
||||
.el-button--primary:focus,
|
||||
.el-button--primary:hover {
|
||||
background: #66b1ff;
|
||||
border-color: #66b1ff;
|
||||
background: var(--color-primary-6);
|
||||
border-color: var(--color-primary-6);
|
||||
color: #fff;
|
||||
}
|
||||
.el-button--primary.is-active,
|
||||
@@ -11266,7 +11266,7 @@
|
||||
}
|
||||
.el-button--text:focus,
|
||||
.el-button--text:hover {
|
||||
color: #66b1ff;
|
||||
color: var(--color-primary-6);
|
||||
border-color: transparent;
|
||||
background-color: transparent;
|
||||
}
|
||||
@@ -11785,7 +11785,7 @@
|
||||
color: var(--color-primary);
|
||||
}
|
||||
.el-link.el-link--primary:hover {
|
||||
color: #66b1ff;
|
||||
color: var(--color-primary-6);
|
||||
}
|
||||
.el-link.el-link--primary.is-disabled {
|
||||
color: #a0cfff;
|
||||
|
||||
+107
@@ -0,0 +1,107 @@
|
||||
@charset "UTF-8";
|
||||
/* 数据量大与遮罩交互冲突优化 */
|
||||
.v-modal.v-modal-leave {
|
||||
display: none;
|
||||
}
|
||||
|
||||
::-webkit-scrollbar {
|
||||
width: 12px;
|
||||
height: 12px;
|
||||
}
|
||||
|
||||
::-webkit-scrollbar-corner {
|
||||
background: transparent;
|
||||
}
|
||||
|
||||
::-webkit-scrollbar-thumb {
|
||||
border-radius: 6px;
|
||||
border: 2px solid transparent;
|
||||
background-color: var(--scrollbar-background-color);
|
||||
background-clip: padding-box;
|
||||
}
|
||||
|
||||
::-webkit-scrollbar-track {
|
||||
background: transparent;
|
||||
border-radius: 5px;
|
||||
}
|
||||
|
||||
.el-dialog__header {
|
||||
padding: 15px 20px 15px 20px;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
border-bottom: 1px solid var(--border-color-lighter);
|
||||
}
|
||||
|
||||
.el-dialog__title {
|
||||
flex: 1;
|
||||
font-size: 16px;
|
||||
margin: 0;
|
||||
color: rgba(0, 0, 0, 0.88);
|
||||
font-weight: 600;
|
||||
line-height: 1.5;
|
||||
word-break: break-word;
|
||||
}
|
||||
|
||||
.el-dialog__headerbtn{
|
||||
top: auto;
|
||||
right: auto;
|
||||
line-height: 1;
|
||||
font-size: 18px;
|
||||
position: static;
|
||||
}
|
||||
|
||||
.el-dialog__footer {
|
||||
padding-bottom: 12px;
|
||||
border-top: 1px solid var(--border-color-lighter);
|
||||
}
|
||||
|
||||
.el-table thead {
|
||||
color: var(--color-text-primary);
|
||||
font-weight: 500;
|
||||
}
|
||||
|
||||
.el-table td.el-table__cell div {
|
||||
color: var(--color-text-primary);
|
||||
}
|
||||
|
||||
|
||||
.el-card {
|
||||
border: none;
|
||||
}
|
||||
|
||||
.el-card + .el-card {
|
||||
margin-top: 15px;
|
||||
}
|
||||
|
||||
.el-message:not(.ele-message-border){
|
||||
background: var(--popover-background-color);
|
||||
-webkit-box-shadow: var(--box-shadow-light);
|
||||
box-shadow: var(--box-shadow-light);
|
||||
border-radius: 2px;
|
||||
border: none;
|
||||
}
|
||||
|
||||
.el-message {
|
||||
min-width: auto;
|
||||
position: fixed;
|
||||
}
|
||||
|
||||
.el-message .el-message__icon {
|
||||
font-size: 18px;
|
||||
}
|
||||
|
||||
.el-message .el-icon-success {
|
||||
color: var(--color-success);
|
||||
}
|
||||
|
||||
.el-message:not(.ele-message-border) .el-message__content {
|
||||
color: inherit;
|
||||
}
|
||||
|
||||
.el-message .el-message__content {
|
||||
line-height: 18px;
|
||||
}
|
||||
|
||||
.el-button{
|
||||
border-radius: 2px;
|
||||
}
|
||||
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
+13308
File diff suppressed because one or more lines are too long
@@ -0,0 +1,648 @@
|
||||
<script>
|
||||
module.exports = {
|
||||
name: "formButton",
|
||||
props: {
|
||||
task_id: {
|
||||
type: String,
|
||||
required: true
|
||||
},
|
||||
// 是否显示审核意见框
|
||||
show_comment: {
|
||||
type: Boolean,
|
||||
default: true
|
||||
},
|
||||
// 自定义按钮配置
|
||||
custom_buttons: {
|
||||
type: Array,
|
||||
default: () => []
|
||||
},
|
||||
// 是否显示流程图
|
||||
show_process_diagram: {
|
||||
type: Boolean,
|
||||
default: true
|
||||
},
|
||||
// 是否显示办理记录
|
||||
show_process_records: {
|
||||
type: Boolean,
|
||||
default: true
|
||||
},
|
||||
// 办理记录展示模式:timeline, table
|
||||
record_display_mode: {
|
||||
type: String,
|
||||
default: "timeline",
|
||||
validator: (value) => {
|
||||
return ["timeline", "table"].includes(value)
|
||||
}
|
||||
},
|
||||
// 业务ID,用于获取流程记录
|
||||
business_id: {
|
||||
type: String,
|
||||
default: ""
|
||||
}
|
||||
},
|
||||
data() {
|
||||
return {
|
||||
loading: false,
|
||||
comment: "", // 审核意见
|
||||
nextNodeInfo: null, // 下一节点信息
|
||||
currentTaskName: "部门审核", // 当前办理节点名称
|
||||
availableActions: [], // 可用操作
|
||||
sequenceFlows: [], // 目标节点
|
||||
selectedAction: "", // 选中的操作类型
|
||||
rejectTaskOptions: [], // 驳回到指定节点的选项
|
||||
selectedRejectTask: "", // 选中的驳回节点
|
||||
assigneeOptions: [], // 执行人选项
|
||||
selectedAssignee: "", // 选中的执行人
|
||||
|
||||
// 控制显示
|
||||
showProcessDiagram: true, // 是否显示流程图
|
||||
showProcessRecords: true, // 是否显示办理记录
|
||||
recordDisplayMode: 'timeline', // 办理记录展示模式:timeline, table
|
||||
|
||||
// 模拟数据 - 办理记录
|
||||
mockProcessRecords: [
|
||||
{
|
||||
nodeName: "发起申请",
|
||||
userName: "张三",
|
||||
time: "2023-05-10 09:30:00",
|
||||
action: "提交申请",
|
||||
comment: "请审批",
|
||||
type: "primary"
|
||||
},
|
||||
{
|
||||
nodeName: "部门审核",
|
||||
userName: "李四",
|
||||
time: "2023-05-10 11:20:00",
|
||||
action: "处理中",
|
||||
comment: "",
|
||||
type: "warning"
|
||||
}
|
||||
]
|
||||
}
|
||||
},
|
||||
created() {
|
||||
if (this.task_id) {
|
||||
this.getNextNodeInfo()
|
||||
}
|
||||
|
||||
// 初始化显示状态
|
||||
this.showProcessDiagram = this.show_process_diagram
|
||||
this.showProcessRecords = this.show_process_records
|
||||
this.recordDisplayMode = this.record_display_mode
|
||||
|
||||
// 模拟获取流程记录
|
||||
this.mockGetProcessRecords()
|
||||
},
|
||||
|
||||
watch: {
|
||||
// 监听props变化
|
||||
show_process_diagram(val) {
|
||||
this.showProcessDiagram = val
|
||||
},
|
||||
show_process_records(val) {
|
||||
this.showProcessRecords = val
|
||||
},
|
||||
record_display_mode(val) {
|
||||
this.recordDisplayMode = val
|
||||
},
|
||||
business_id: {
|
||||
handler(val) {
|
||||
if (val) {
|
||||
// 清空现有记录
|
||||
this.mockProcessRecords = []
|
||||
// 重新获取流程记录
|
||||
this.mockGetProcessRecords()
|
||||
}
|
||||
},
|
||||
immediate: true
|
||||
}
|
||||
},
|
||||
methods: {
|
||||
// 获取下一节点信息
|
||||
getNextNodeInfo() {
|
||||
this.loading = true
|
||||
this.$axios
|
||||
.post("/easy-flowable/task/nextNodeVariables/" + this.task_id)
|
||||
.then((res) => {
|
||||
if (res.code === 200) {
|
||||
this.nextNodeInfo = res.result
|
||||
// 获取当前办理节点名称
|
||||
if (res.result.task && res.result.task.name) {
|
||||
this.currentTaskName = res.result.task.name
|
||||
}
|
||||
// 处理可用操作
|
||||
if (res.result.attributes && res.result.attributes.actions) {
|
||||
this.availableActions = res.result.attributes.actions
|
||||
}
|
||||
// 处理目标节点
|
||||
if (res.result.sequenceFlow) {
|
||||
this.sequenceFlows = res.result.sequenceFlow
|
||||
}
|
||||
} else {
|
||||
this.$message.error(res.msg || "获取下一节点信息失败")
|
||||
}
|
||||
})
|
||||
.catch((error) => {
|
||||
console.error("获取下一节点信息失败", error)
|
||||
this.$message.error("获取下一节点信息失败")
|
||||
})
|
||||
.finally(() => {
|
||||
this.loading = false
|
||||
})
|
||||
},
|
||||
// 获取可驳回的节点列表
|
||||
getRejectTaskList() {
|
||||
this.loading = true
|
||||
this.$axios
|
||||
.get("/easy-flowable/task/flowBackNodes/" + this.task_id)
|
||||
.then((res) => {
|
||||
if (res.code === 0 && res.result) {
|
||||
this.rejectTaskOptions = res.result.map((item) => ({
|
||||
label: item.nodeName,
|
||||
value: item.nodeId
|
||||
}))
|
||||
if (this.rejectTaskOptions.length > 0) {
|
||||
this.selectedRejectTask = this.rejectTaskOptions[0].value
|
||||
}
|
||||
} else {
|
||||
this.$message.error(res.msg || "获取可驳回节点失败")
|
||||
}
|
||||
})
|
||||
.catch((error) => {
|
||||
console.error("获取可驳回节点失败", error)
|
||||
this.$message.error("获取可驳回节点失败")
|
||||
})
|
||||
.finally(() => {
|
||||
this.loading = false
|
||||
})
|
||||
},
|
||||
// 处理按钮点击
|
||||
handleAction(action) {
|
||||
this.selectedAction = action
|
||||
|
||||
// 如果是驳回到指定节点,需要获取可驳回的节点列表
|
||||
if (action === "REJECT_TO_TASK") {
|
||||
this.getRejectTaskList()
|
||||
return
|
||||
}
|
||||
|
||||
// 执行操作
|
||||
this.submitAction()
|
||||
},
|
||||
// 提交操作
|
||||
submitAction() {
|
||||
if (this.show_comment && !this.comment && ["AGREE", "REJECT", "REJECT_TO_TASK", "REBUT"].includes(this.selectedAction)) {
|
||||
this.$message.warning("请填写审核意见")
|
||||
return
|
||||
}
|
||||
|
||||
const params = {
|
||||
taskId: this.task_id,
|
||||
comment: this.comment,
|
||||
type: this.getActionCode(this.selectedAction)
|
||||
}
|
||||
|
||||
// 添加目标节点变量(自动选择第一个)
|
||||
if (this.sequenceFlows.length > 0 && ["AGREE"].includes(this.selectedAction)) {
|
||||
params.variables = {
|
||||
sequenceFlow: this.sequenceFlows[0].value
|
||||
}
|
||||
}
|
||||
|
||||
// 添加驳回节点信息
|
||||
if (this.selectedAction === "REJECT_TO_TASK" && this.selectedRejectTask) {
|
||||
params.targetTaskDefinitionKey = this.selectedRejectTask
|
||||
}
|
||||
|
||||
this.loading = true
|
||||
this.$axios
|
||||
.post("/easy-flowable/task/complete", params)
|
||||
.then((res) => {
|
||||
if (res.code === 0) {
|
||||
this.$message.success("操作成功")
|
||||
this.$emit("success", {
|
||||
action: this.selectedAction,
|
||||
result: res.result
|
||||
})
|
||||
} else {
|
||||
this.$message.error(res.msg || "操作失败")
|
||||
}
|
||||
})
|
||||
.catch((error) => {
|
||||
console.error("操作失败", error)
|
||||
this.$message.error("操作失败")
|
||||
})
|
||||
.finally(() => {
|
||||
this.loading = false
|
||||
})
|
||||
},
|
||||
// 获取操作类型代码
|
||||
getActionCode(action) {
|
||||
const actionMap = {
|
||||
START: "0",
|
||||
AGREE: "1",
|
||||
REBUT: "2",
|
||||
REVOCATION: "3",
|
||||
REJECT: "4",
|
||||
REJECT_TO_TASK: "5",
|
||||
DELEGATE: "6",
|
||||
ASSIGN: "7",
|
||||
STOP: "8",
|
||||
BEFORE_SIGN: "9",
|
||||
AFTER_SIGN: "10",
|
||||
CANCELLATION: "11",
|
||||
ADD_COMMENT: "12",
|
||||
DEL_COMMENT: "13",
|
||||
RESUBMIT: "14"
|
||||
}
|
||||
return actionMap[action] || "1"
|
||||
},
|
||||
// 获取操作按钮文本
|
||||
getActionText(action) {
|
||||
const actionTextMap = {
|
||||
START: "启动流程",
|
||||
AGREE: "同意",
|
||||
REBUT: "拒绝",
|
||||
REVOCATION: "撤回",
|
||||
REJECT: "驳回",
|
||||
REJECT_TO_TASK: "驳回到指定节点",
|
||||
DELEGATE: "委派",
|
||||
ASSIGN: "转办",
|
||||
STOP: "终止",
|
||||
BEFORE_SIGN: "前加签",
|
||||
AFTER_SIGN: "后加签",
|
||||
CANCELLATION: "作废",
|
||||
ADD_COMMENT: "添加评论",
|
||||
DEL_COMMENT: "删除评论",
|
||||
RESUBMIT: "重新提交"
|
||||
}
|
||||
return actionTextMap[action] || action
|
||||
},
|
||||
// 获取操作按钮类型
|
||||
getActionType(action) {
|
||||
const typeMap = {
|
||||
AGREE: "primary",
|
||||
REBUT: "danger",
|
||||
REJECT: "warning",
|
||||
REJECT_TO_TASK: "warning"
|
||||
}
|
||||
return typeMap[action] || "default"
|
||||
},
|
||||
|
||||
// 模拟获取流程记录
|
||||
mockGetProcessRecords() {
|
||||
// 这里可以根据实际需求调整模拟数据
|
||||
// 实际项目中,可以通过API获取真实数据
|
||||
// 例如:this.$axios.post("/platform/wf/processCommon/approvalRecord", { businessNo: this.business_id })
|
||||
|
||||
// 模拟异步获取数据
|
||||
setTimeout(() => {
|
||||
// 如果已经有模拟数据,则不再添加
|
||||
if (this.mockProcessRecords.length <= 2) {
|
||||
// 添加更多模拟数据
|
||||
this.mockProcessRecords.push(
|
||||
{
|
||||
nodeName: "主管审核",
|
||||
userName: "王五",
|
||||
time: "2023-05-09 14:30:00",
|
||||
action: "同意",
|
||||
comment: "同意申请,请总经理审批",
|
||||
type: "success"
|
||||
},
|
||||
{
|
||||
nodeName: "发起申请",
|
||||
userName: "张三",
|
||||
time: "2023-05-09 10:15:00",
|
||||
action: "提交申请",
|
||||
comment: "请审批我的申请",
|
||||
type: "info"
|
||||
}
|
||||
)
|
||||
}
|
||||
}, 1000)
|
||||
}
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<div class="form-button-container">
|
||||
<!-- 主要内容区域 -->
|
||||
<div class="main-content">
|
||||
<!-- 表单信息插槽 -->
|
||||
<div class="form-info-container">
|
||||
<slot name="form-info"></slot>
|
||||
</div>
|
||||
|
||||
<!-- 流程图展示 -->
|
||||
<div class="process-diagram-container" v-if="showProcessDiagram">
|
||||
<div class="section-title">流程图</div>
|
||||
<div class="process-diagram">
|
||||
<!-- 模拟流程图 -->
|
||||
<div class="mock-process-diagram">
|
||||
<div class="mock-node start">开始</div>
|
||||
<div class="mock-arrow"></div>
|
||||
<div class="mock-node" :class="{ active: currentTaskName === '部门审核' }">部门审核</div>
|
||||
<div class="mock-arrow"></div>
|
||||
<div class="mock-node">主管审核</div>
|
||||
<div class="mock-arrow"></div>
|
||||
<div class="mock-node">总经理审核</div>
|
||||
<div class="mock-arrow"></div>
|
||||
<div class="mock-node end">结束</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- 办理记录 -->
|
||||
<div class="process-records-container" v-if="showProcessRecords">
|
||||
<div class="section-title">
|
||||
<span>办理记录</span>
|
||||
<div class="display-mode-selector">
|
||||
<el-radio-group v-model="recordDisplayMode" size="small">
|
||||
<el-radio-button label="timeline">时间线</el-radio-button>
|
||||
<el-radio-button label="table">表格</el-radio-button>
|
||||
</el-radio-group>
|
||||
</div>
|
||||
</div>
|
||||
<div class="process-records">
|
||||
<!-- 时间线模式 -->
|
||||
<el-timeline v-if="recordDisplayMode === 'timeline'">
|
||||
<el-timeline-item v-for="(record, index) in mockProcessRecords" :key="index" :timestamp="record.time" :type="record.type">
|
||||
<div class="record-content">
|
||||
<div class="record-title">{{ record.nodeName }} - {{ record.userName }}</div>
|
||||
<div class="record-action">{{ record.action }}</div>
|
||||
<div class="record-comment" v-if="record.comment">{{ record.comment }}</div>
|
||||
</div>
|
||||
</el-timeline-item>
|
||||
</el-timeline>
|
||||
|
||||
<!-- 表格模式 -->
|
||||
<el-table v-else-if="recordDisplayMode === 'table'" :data="mockProcessRecords" stripe style="width: 100%">
|
||||
<el-table-column prop="nodeName" label="节点名称" width="120"></el-table-column>
|
||||
<el-table-column prop="userName" label="操作人" width="100"></el-table-column>
|
||||
<el-table-column prop="time" label="操作时间" width="160"></el-table-column>
|
||||
<el-table-column prop="action" label="操作类型" width="100">
|
||||
<template slot-scope="scope">
|
||||
<el-tag :type="scope.row.type">{{ scope.row.action }}</el-tag>
|
||||
</template>
|
||||
</el-table-column>
|
||||
<el-table-column prop="comment" label="操作意见">
|
||||
<template slot-scope="scope">
|
||||
<span v-if="scope.row.comment">{{ scope.row.comment }}</span>
|
||||
<span v-else class="no-comment">无</span>
|
||||
</template>
|
||||
</el-table-column>
|
||||
</el-table>
|
||||
|
||||
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- 底部固定操作区域 -->
|
||||
<div class="footer-actions">
|
||||
<!-- 当前办理节点 -->
|
||||
<div v-if="currentTaskName" class="current-task-container">
|
||||
<div class="current-task-label">当前节点:</div>
|
||||
<div class="current-task-info">{{ currentTaskName }}</div>
|
||||
</div>
|
||||
|
||||
<!-- 目标节点展示 -->
|
||||
<div v-if="sequenceFlows.length > 0" class="flow-container">
|
||||
<div class="flow-label">目标节点:</div>
|
||||
<div class="target-node-info">
|
||||
<span v-for="item in sequenceFlows" :key="item.value">{{ item.label }}</span>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- 审核意见 -->
|
||||
<div v-if="show_comment" class="comment-container">
|
||||
<div class="comment-label">审核意见:</div>
|
||||
<el-input v-model="comment" type="textarea" :rows="3" placeholder="请输入审核意见"></el-input>
|
||||
</div>
|
||||
|
||||
<!-- 驳回到指定节点选择 -->
|
||||
<div v-if="selectedAction === 'REJECT_TO_TASK' && rejectTaskOptions.length > 0" class="reject-container">
|
||||
<div class="reject-label">驳回到:</div>
|
||||
<el-select v-model="selectedRejectTask" placeholder="请选择驳回节点">
|
||||
<el-option v-for="item in rejectTaskOptions" :key="item.value" :label="item.label" :value="item.value"></el-option>
|
||||
</el-select>
|
||||
<el-button type="primary" @click="submitAction">确认</el-button>
|
||||
<el-button @click="selectedAction = ''">取消</el-button>
|
||||
</div>
|
||||
|
||||
<!-- 操作按钮 -->
|
||||
<div class="button-container">
|
||||
<!-- 系统预设按钮 -->
|
||||
<template v-for="action in availableActions">
|
||||
<el-button
|
||||
:key="action"
|
||||
:type="getActionType(action)"
|
||||
:loading="loading && selectedAction === action"
|
||||
@click="handleAction(action)"
|
||||
>
|
||||
{{ getActionText(action) }}
|
||||
</el-button>
|
||||
</template>
|
||||
|
||||
<!-- 自定义按钮 -->
|
||||
<template v-for="(button, index) in custom_buttons">
|
||||
<el-button
|
||||
:key="'custom-' + index"
|
||||
:type="button.type || 'default'"
|
||||
:loading="loading && selectedAction === button.action"
|
||||
@click="handleAction(button.action)"
|
||||
>
|
||||
{{ button.text }}
|
||||
</el-button>
|
||||
</template>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<style scoped>
|
||||
.form-button-container {
|
||||
/*display: flex;
|
||||
//flex-direction: column;*/
|
||||
min-height: 500px;
|
||||
position: relative;
|
||||
height: 100vh; /* 使用视口高度 */
|
||||
}
|
||||
|
||||
/* 主要内容区域 */
|
||||
.main-content {
|
||||
flex: 1;
|
||||
overflow-y: auto;
|
||||
padding-bottom: 20px;
|
||||
}
|
||||
|
||||
/* 表单信息容器 */
|
||||
.form-info-container {
|
||||
margin-bottom: 20px;
|
||||
}
|
||||
|
||||
/* 流程图和办理记录共用样式 */
|
||||
.process-diagram-container,
|
||||
.process-records-container {
|
||||
margin-bottom: 30px;
|
||||
border: 1px solid #ebeef5;
|
||||
border-radius: 4px;
|
||||
padding: 15px;
|
||||
background-color: #fff;
|
||||
}
|
||||
|
||||
.section-title {
|
||||
font-size: 16px;
|
||||
font-weight: bold;
|
||||
margin-bottom: 15px;
|
||||
padding-bottom: 10px;
|
||||
border-bottom: 1px solid #ebeef5;
|
||||
display: flex;
|
||||
justify-content: space-between;
|
||||
align-items: center;
|
||||
}
|
||||
|
||||
.display-mode-selector {
|
||||
margin-left: auto;
|
||||
}
|
||||
|
||||
/* 流程图样式 */
|
||||
.process-diagram {
|
||||
min-height: 120px;
|
||||
}
|
||||
|
||||
.mock-process-diagram {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
flex-wrap: wrap;
|
||||
padding: 20px 0;
|
||||
}
|
||||
|
||||
.mock-node {
|
||||
padding: 10px 15px;
|
||||
background-color: #f5f7fa;
|
||||
border: 1px solid #e4e7ed;
|
||||
border-radius: 4px;
|
||||
margin: 0 5px;
|
||||
position: relative;
|
||||
}
|
||||
|
||||
.mock-node.start {
|
||||
background-color: #f0f9eb;
|
||||
border-color: #e1f3d8;
|
||||
color: #67c23a;
|
||||
}
|
||||
|
||||
.mock-node.end {
|
||||
background-color: #f0f2f5;
|
||||
border-color: #dcdfe6;
|
||||
color: #909399;
|
||||
}
|
||||
|
||||
.mock-node.active {
|
||||
background-color: #ecf5ff;
|
||||
border-color: #d9ecff;
|
||||
color: #409eff;
|
||||
font-weight: bold;
|
||||
}
|
||||
|
||||
.mock-arrow {
|
||||
width: 30px;
|
||||
height: 2px;
|
||||
background-color: #dcdfe6;
|
||||
position: relative;
|
||||
}
|
||||
|
||||
.mock-arrow:after {
|
||||
content: "";
|
||||
position: absolute;
|
||||
right: 0;
|
||||
top: -3px;
|
||||
width: 0;
|
||||
height: 0;
|
||||
border-style: solid;
|
||||
border-width: 4px 0 4px 6px;
|
||||
border-color: transparent transparent transparent #dcdfe6;
|
||||
}
|
||||
|
||||
/* 办理记录样式 */
|
||||
.process-records {
|
||||
padding: 10px 0;
|
||||
}
|
||||
|
||||
/* 时间线模式样式 */
|
||||
.record-content {
|
||||
padding: 5px 0;
|
||||
}
|
||||
|
||||
.record-title {
|
||||
font-weight: bold;
|
||||
margin-bottom: 5px;
|
||||
}
|
||||
|
||||
.record-action {
|
||||
color: #409eff;
|
||||
margin-bottom: 5px;
|
||||
}
|
||||
|
||||
.record-comment {
|
||||
color: #606266;
|
||||
background-color: #f5f7fa;
|
||||
padding: 8px;
|
||||
border-radius: 4px;
|
||||
margin-top: 5px;
|
||||
}
|
||||
|
||||
/* 表格模式样式 */
|
||||
.no-comment {
|
||||
color: #909399;
|
||||
font-style: italic;
|
||||
}
|
||||
|
||||
|
||||
|
||||
/* 底部固定操作区域 */
|
||||
.footer-actions {
|
||||
border-top: 1px solid #ebeef5;
|
||||
padding: 20px;
|
||||
background-color: #fff;
|
||||
//position: sticky;
|
||||
//bottom: 0;
|
||||
z-index: 10;
|
||||
box-shadow: 0 -2px 10px rgba(0, 0, 0, 0.05);
|
||||
}
|
||||
|
||||
.comment-container,
|
||||
.current-task-container,
|
||||
.flow-container,
|
||||
.reject-container {
|
||||
margin-bottom: 15px;
|
||||
}
|
||||
|
||||
.comment-label,
|
||||
.current-task-label,
|
||||
.flow-label,
|
||||
.reject-label {
|
||||
margin-bottom: 5px;
|
||||
font-weight: bold;
|
||||
}
|
||||
|
||||
.current-task-info {
|
||||
padding: 5px 0;
|
||||
line-height: 1.5;
|
||||
}
|
||||
|
||||
.target-node-info {
|
||||
padding: 5px 0;
|
||||
line-height: 1.5;
|
||||
}
|
||||
|
||||
.button-container {
|
||||
margin-top: 20px;
|
||||
display: flex;
|
||||
flex-wrap: wrap;
|
||||
gap: 10px;
|
||||
}
|
||||
</style>
|
||||
@@ -0,0 +1,728 @@
|
||||
<template>
|
||||
<div class="flow-container">
|
||||
<!-- 页面标题栏 -->
|
||||
<div class="page-header">
|
||||
<div class="header-content">
|
||||
<div class="title-section">
|
||||
<h2 class="page-title">{{ pageTitle }}</h2>
|
||||
<div class="page-breadcrumb">
|
||||
<span>工作流管理</span>
|
||||
<span class="separator">></span>
|
||||
<span>{{ isNewApplication ? "发起申请" : "任务处理" }}</span>
|
||||
</div>
|
||||
</div>
|
||||
<div class="status-section">
|
||||
<span class="status-label">状态:</span>
|
||||
<span class="status-badge" :class="statusClass">{{ processStatusText }}</span>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- 主要内容区域 -->
|
||||
<div class="main-content">
|
||||
<!-- 左侧内容 -->
|
||||
<div class="content-left">
|
||||
<!-- 流程基本信息 -->
|
||||
<div class="info-panel">
|
||||
<div class="panel-header">
|
||||
<h3 class="panel-title">流程信息</h3>
|
||||
<div class="panel-actions">
|
||||
<el-button size="small" type="text" @click="showProcessDiagram" v-if="canShowDiagram">
|
||||
<i class="el-icon-view"></i>
|
||||
查看流程图
|
||||
</el-button>
|
||||
</div>
|
||||
</div>
|
||||
<div class="panel-content">
|
||||
<div class="info-table">
|
||||
<!-- 新申请场景 -->
|
||||
<template v-if="isNewApplication">
|
||||
<div class="info-row">
|
||||
<div class="info-label">流程名称:</div>
|
||||
<div class="info-value">{{ processDefinition.displayName || processDefinition.name }}</div>
|
||||
</div>
|
||||
<div class="info-row">
|
||||
<div class="info-label">流程说明:</div>
|
||||
<div class="info-value">{{ processDefinition.description }}</div>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<!-- 已有流程场景 -->
|
||||
<template v-else-if="isExistingProcess">
|
||||
<div class="info-row">
|
||||
<div class="info-label">流程名称:</div>
|
||||
<div class="info-value">{{ processInstance.displayName }}</div>
|
||||
</div>
|
||||
<div class="info-row">
|
||||
<div class="info-label">发起人:</div>
|
||||
<div class="info-value">{{ processInstance?.ext?.initiatorName || "-" }}</div>
|
||||
</div>
|
||||
<div class="info-row">
|
||||
<div class="info-label">发起时间:</div>
|
||||
<div class="info-value">{{ formatDate(processInstance.createdAt) }}</div>
|
||||
</div>
|
||||
</template>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- 历史办理过程面板 -->
|
||||
<div v-if="shouldShowHistoryProcess" class="history-panel">
|
||||
<div class="panel-header">
|
||||
<h3 class="panel-title">办理过程</h3>
|
||||
</div>
|
||||
<div class="panel-content">
|
||||
<div id="history-process-container" class="form-content">
|
||||
<div v-if="pjaxLoading.historyProcess" class="loading-state">
|
||||
<i class="el-icon-loading"></i>
|
||||
<span>正在加载历史办理过程...</span>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- 表单处理区域 -->
|
||||
<div class="form-panel" v-if="isNewApplication || todoTasks.map((v) => v.id).includes(taskId)">
|
||||
<div class="panel-header">
|
||||
<h3 class="panel-title">{{ formPanelTitle }}</h3>
|
||||
</div>
|
||||
<div class="panel-content">
|
||||
<!-- 新申请表单 -->
|
||||
<div v-if="isNewApplication" id="application-form-container" class="form-content">
|
||||
<div v-if="pjaxLoading.apply" class="loading-state">
|
||||
<i class="el-icon-loading"></i>
|
||||
<span>正在加载申请表单...</span>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- 当前任务表单 -->
|
||||
<div v-if="shouldShowTaskForm" id="task-form-container" class="form-content">
|
||||
<div v-if="pjaxLoading.taskForm" class="loading-state">
|
||||
<i class="el-icon-loading"></i>
|
||||
<span>正在加载任务表单...</span>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- 右侧审批记录 -->
|
||||
<!-- <div class="content-right" v-if="isExistingProcess">-->
|
||||
<!-- <snaker-flow-history-approval :task_id="taskId"></snaker-flow-history-approval>-->
|
||||
<!-- </div>-->
|
||||
</div>
|
||||
|
||||
<!-- 流程图对话框 -->
|
||||
<el-dialog title="流程图预览" :visible.sync="designVisible" width="80%" top="8vh">
|
||||
<div class="diagram-viewer">
|
||||
<iframe v-if="designVisible" :src="designUrl" frameborder="0"></iframe>
|
||||
</div>
|
||||
</el-dialog>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
module.exports = {
|
||||
name: "SnakerFlow",
|
||||
data() {
|
||||
return {
|
||||
// URL参数
|
||||
taskId: GetQueryString("taskId") ? parseInt(GetQueryString("taskId")) : null,
|
||||
instanceId: GetQueryString("instanceId"),
|
||||
businessId: GetQueryString("businessId"),
|
||||
defineKey: GetQueryString("defineKey"), // 新增:流程定义KEY
|
||||
|
||||
processInstance: {},
|
||||
//流程定义信息
|
||||
processDefinition: {},
|
||||
todoTasks: [],
|
||||
currentTask: {},
|
||||
|
||||
// 加载状态
|
||||
loading: false,
|
||||
// 错误信息
|
||||
error: null,
|
||||
|
||||
// PJAX 加载状态
|
||||
pjaxLoading: {
|
||||
apply: false,
|
||||
taskForm: false,
|
||||
historyProcess: false
|
||||
},
|
||||
|
||||
// 显示历史记录
|
||||
showHistory: false,
|
||||
|
||||
// 流程图相关
|
||||
designVisible: false,
|
||||
designUrl: "",
|
||||
|
||||
// 流程状态枚举映射
|
||||
processStatusMap: {
|
||||
10: { text: "进行中", class: "doing" },
|
||||
20: { text: "已完成", class: "finished" },
|
||||
30: { text: "已撤回", class: "withdraw" },
|
||||
40: { text: "强行终止", class: "interrupt" },
|
||||
45: { text: "已拒绝", class: "reject" },
|
||||
50: { text: "挂起", class: "pending" },
|
||||
99: { text: "已废弃", class: "abandon" }
|
||||
},
|
||||
|
||||
// 任务状态枚举
|
||||
taskStateEnum: {
|
||||
DOING: 10,
|
||||
FINISHED: 20,
|
||||
WITHDRAW: 30,
|
||||
INTERRUPT: 40,
|
||||
PENDING: 50,
|
||||
ABANDON: 99
|
||||
},
|
||||
|
||||
// 任务类型枚举
|
||||
performTypeEnum: {
|
||||
NORMAL: 0, // 普通任务
|
||||
COUNTERSIGN: 1 // 会签任务
|
||||
}
|
||||
}
|
||||
},
|
||||
computed: {
|
||||
// 页面标题
|
||||
pageTitle() {
|
||||
if (this.isNewApplication) {
|
||||
return this.processDefinition.displayName || this.processDefinition.name || "发起申请"
|
||||
} else {
|
||||
return this.processInstance.displayName || "任务处理"
|
||||
}
|
||||
},
|
||||
|
||||
// 流程状态文本
|
||||
processStatusText() {
|
||||
if (this.isNewApplication) {
|
||||
return "待提交"
|
||||
} else {
|
||||
return this.processStatusMap[this.processInstance.state]?.text || "未知状态"
|
||||
}
|
||||
},
|
||||
|
||||
// 状态样式类
|
||||
statusClass() {
|
||||
if (this.isNewApplication) {
|
||||
return "status-pending"
|
||||
} else {
|
||||
const statusClass = this.processStatusMap[this.processInstance.state]?.class
|
||||
return `status-${statusClass || "unknown"}`
|
||||
}
|
||||
},
|
||||
|
||||
// 表单面板标题
|
||||
formPanelTitle() {
|
||||
if (this.isNewApplication) {
|
||||
return "申请表单"
|
||||
} else if (this.shouldShowTaskForm) {
|
||||
return this.currentTask.displayName || "任务表单"
|
||||
} else if (this.shouldShowHistoryProcess) {
|
||||
return "办理过程"
|
||||
} else {
|
||||
return "表单信息"
|
||||
}
|
||||
},
|
||||
|
||||
// 是否显示历史办理过程
|
||||
shouldShowHistoryProcess() {
|
||||
// debugger
|
||||
// return this.businessId && this.isTaskInProgress && !this.isFirstTaskNode
|
||||
return true
|
||||
},
|
||||
|
||||
// 是否显示任务表单
|
||||
shouldShowTaskForm() {
|
||||
debugger
|
||||
return this.taskId != null
|
||||
},
|
||||
|
||||
// 是否可以显示流程图
|
||||
canShowDiagram() {
|
||||
return (this.isNewApplication && this.processDefinition.id) || (this.isExistingProcess && this.processInstance.processId)
|
||||
},
|
||||
|
||||
// 判断是否为新申请
|
||||
isNewApplication() {
|
||||
return !this.taskId && !this.instanceId && this.defineKey
|
||||
},
|
||||
|
||||
// 判断是否为已有流程实例
|
||||
isExistingProcess() {
|
||||
return this.taskId || this.instanceId
|
||||
},
|
||||
|
||||
// 判断任务是否进行中
|
||||
isTaskInProgress() {
|
||||
return this.currentTask && this.currentTask.taskState === this.taskStateEnum.DOING
|
||||
},
|
||||
|
||||
// 判断是否为第一个任务节点
|
||||
isFirstTaskNode() {
|
||||
return this.currentTask && this.currentTask.ext && this.currentTask.ext.isFirstTaskNode
|
||||
},
|
||||
|
||||
// 流程图预览URL
|
||||
processDesignUrl() {
|
||||
if (this.isNewApplication && this.processDefinition.id) {
|
||||
return `/flow/define/preview?id=${this.processDefinition.id}`
|
||||
} else if (this.isExistingProcess && this.processInstance.processId) {
|
||||
return `/flow/define/preview?id=${this.processInstance.processId}`
|
||||
}
|
||||
return ""
|
||||
}
|
||||
},
|
||||
created() {
|
||||
this.initComponent()
|
||||
// 监听
|
||||
window.addEventListener("message", (event) => {
|
||||
if (event.data.type === "task-complete") {
|
||||
this.initComponent()
|
||||
}
|
||||
})
|
||||
},
|
||||
methods: {
|
||||
// 初始化组件
|
||||
async initComponent() {
|
||||
this.loading = true
|
||||
|
||||
debugger
|
||||
|
||||
if (this.isNewApplication) {
|
||||
// 新申请:加载流程定义信息
|
||||
await this.loadProcessDefinition()
|
||||
// 加载流程申请表单
|
||||
await this.loadApplicationForm()
|
||||
} else if (this.isExistingProcess) {
|
||||
// 已有流程:加载流程实例信息
|
||||
await this.loadProcessInstance()
|
||||
// 加载任务信息
|
||||
await this.loadCurrentTask()
|
||||
// 如果有businessId且不是第一个任务节点,加载历史办理过程
|
||||
if (this.businessId) {
|
||||
await this.loadHistoryProcess()
|
||||
}
|
||||
} else {
|
||||
console.warn("URL中缺少必要的参数(defineKey、taskId或instanceId),无法初始化组件")
|
||||
this.loading = false
|
||||
return
|
||||
}
|
||||
|
||||
this.loading = false
|
||||
},
|
||||
|
||||
// 加载流程定义信息
|
||||
async loadProcessDefinition() {
|
||||
if (!this.defineKey) return
|
||||
|
||||
try {
|
||||
const response = await $.get("/flow/common/defineInfo", { defineKey: this.defineKey })
|
||||
if (response.code === 0) {
|
||||
this.processDefinition = response.data
|
||||
}
|
||||
} catch (error) {
|
||||
console.error("加载流程定义信息失败:", error)
|
||||
}
|
||||
},
|
||||
|
||||
// 加载申请表单
|
||||
async loadApplicationForm() {
|
||||
debugger
|
||||
if (!this.defineKey || !this.processDefinition.instanceUrl) return
|
||||
|
||||
this.pjaxLoading.apply = true
|
||||
|
||||
$.pjax({
|
||||
url: this.processDefinition.instanceUrl,
|
||||
container: "#application-form-container",
|
||||
push: false,
|
||||
replace: false,
|
||||
timeout: 10000
|
||||
})
|
||||
.done(() => {
|
||||
this.pjaxLoading.apply = false
|
||||
})
|
||||
.fail(() => {
|
||||
this.pjaxLoading.apply = false
|
||||
console.log(this.processDefinition.instanceUrl, "申请表单加载失败")
|
||||
})
|
||||
},
|
||||
|
||||
// 加载流程实例信息
|
||||
async loadProcessInstance() {
|
||||
if (!this.instanceId) return
|
||||
const { code, data, msg } = await $.get("/flow/common/instanceInfo", { instanceId: this.instanceId })
|
||||
if (code === 0) {
|
||||
this.processInstance = data.processInstance
|
||||
this.todoTasks = data.todoTasks
|
||||
}
|
||||
},
|
||||
|
||||
// 加载任务信息
|
||||
async loadCurrentTask() {
|
||||
if (!this.taskId) return
|
||||
$.get("/flow/common/taskInfo", { taskId: this.taskId }, (response) => {
|
||||
if (response.code === 0) {
|
||||
this.currentTask = response.data
|
||||
this.loadTaskForm()
|
||||
}
|
||||
})
|
||||
},
|
||||
|
||||
// 加载任务表单
|
||||
async loadTaskForm() {
|
||||
if (!this.taskId || !this.currentTask?.taskModel?.form) return
|
||||
|
||||
if (!this.todoTasks.map((v) => v.id).includes(this.taskId)) {
|
||||
return
|
||||
}
|
||||
|
||||
this.pjaxLoading.taskForm = true
|
||||
|
||||
$.pjax({
|
||||
url: this.currentTask.taskModel.form,
|
||||
container: "#task-form-container",
|
||||
push: false,
|
||||
replace: false,
|
||||
timeout: 10000
|
||||
})
|
||||
.done(() => {
|
||||
this.pjaxLoading.taskForm = false
|
||||
})
|
||||
.fail(() => {
|
||||
this.pjaxLoading.taskForm = false
|
||||
console.log(this.currentTask.taskModel.form, "任务表单加载失败")
|
||||
})
|
||||
},
|
||||
|
||||
// 加载历史办理过程
|
||||
async loadHistoryProcess() {
|
||||
if (!this.businessId) return
|
||||
|
||||
this.pjaxLoading.historyProcess = true
|
||||
|
||||
$.pjax({
|
||||
url: `/platform/article/common/fullForm?businessId=${this.businessId}`,
|
||||
container: "#history-process-container",
|
||||
push: false,
|
||||
replace: false,
|
||||
timeout: 10000
|
||||
})
|
||||
.done(() => {
|
||||
this.pjaxLoading.historyProcess = false
|
||||
})
|
||||
.fail(() => {
|
||||
this.pjaxLoading.historyProcess = false
|
||||
console.log("历史办理过程加载失败")
|
||||
})
|
||||
},
|
||||
|
||||
// 显示流程图
|
||||
showProcessDiagram() {
|
||||
if (this.processDesignUrl) {
|
||||
this.designUrl = this.processDesignUrl
|
||||
this.designVisible = true
|
||||
}
|
||||
},
|
||||
|
||||
// 获取状态文本
|
||||
getStatusText(state) {
|
||||
return this.processStatusMap[state]?.text || "未知状态"
|
||||
},
|
||||
|
||||
// 获取状态样式类
|
||||
getStatusClass(state) {
|
||||
return `status-${this.processStatusMap[state]?.class || "unknown"}`
|
||||
},
|
||||
|
||||
// 格式化日期
|
||||
formatDate(dateStr) {
|
||||
if (!dateStr) return "-"
|
||||
return new Date(dateStr).toLocaleString("zh-CN", {
|
||||
year: "numeric",
|
||||
month: "2-digit",
|
||||
day: "2-digit",
|
||||
hour: "2-digit",
|
||||
minute: "2-digit"
|
||||
})
|
||||
}
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
||||
<style scoped>
|
||||
/* 简洁OA风格样式 */
|
||||
.flow-container {
|
||||
background-color: #f5f6fa;
|
||||
min-height: 100vh;
|
||||
font-family: "Microsoft YaHei", Arial, sans-serif;
|
||||
}
|
||||
|
||||
/* 页面头部 - 固定在顶部 */
|
||||
.page-header {
|
||||
background: white;
|
||||
border-bottom: 1px solid #e4e7ed;
|
||||
padding: 16px 0;
|
||||
position: fixed;
|
||||
top: 64px;
|
||||
left: 0;
|
||||
right: 0;
|
||||
z-index: 1000;
|
||||
box-shadow: 0 2px 4px rgba(0, 0, 0, 0.1);
|
||||
}
|
||||
|
||||
/* 主要内容区域 - 添加顶部间距 */
|
||||
.main-content {
|
||||
max-width: 1200px;
|
||||
margin: 0 auto;
|
||||
margin-top: 80px; /* 为固定头部留出空间 */
|
||||
padding: 20px;
|
||||
display: flex;
|
||||
gap: 20px;
|
||||
}
|
||||
|
||||
.header-content {
|
||||
max-width: 1200px;
|
||||
margin: 0 auto;
|
||||
padding: 0 20px;
|
||||
display: flex;
|
||||
justify-content: space-between;
|
||||
align-items: center;
|
||||
}
|
||||
|
||||
.title-section .page-title {
|
||||
font-size: 20px;
|
||||
font-weight: 600;
|
||||
color: #303133;
|
||||
margin: 0 0 4px 0;
|
||||
}
|
||||
|
||||
.page-breadcrumb {
|
||||
font-size: 12px;
|
||||
color: #909399;
|
||||
}
|
||||
|
||||
.separator {
|
||||
margin: 0 6px;
|
||||
}
|
||||
|
||||
.status-section {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
gap: 8px;
|
||||
}
|
||||
|
||||
.status-label {
|
||||
font-size: 14px;
|
||||
color: #606266;
|
||||
}
|
||||
|
||||
.status-badge {
|
||||
padding: 4px 12px;
|
||||
border-radius: 4px;
|
||||
font-size: 12px;
|
||||
font-weight: 500;
|
||||
}
|
||||
|
||||
.status-pending {
|
||||
background: #fdf6ec;
|
||||
color: #e6a23c;
|
||||
}
|
||||
|
||||
.status-doing {
|
||||
background: #ecf5ff;
|
||||
color: var(--color-primary);
|
||||
}
|
||||
|
||||
.status-finished {
|
||||
background: #f0f9ff;
|
||||
color: #67c23a;
|
||||
}
|
||||
|
||||
.status-withdraw {
|
||||
background: #f4f4f5;
|
||||
color: #909399;
|
||||
}
|
||||
|
||||
.status-interrupt {
|
||||
background: #fef0f0;
|
||||
color: #f56c6c;
|
||||
}
|
||||
|
||||
.status-reject {
|
||||
background: #fef0f0;
|
||||
color: #f56c6c;
|
||||
}
|
||||
|
||||
.content-left {
|
||||
flex: 1;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
gap: 16px;
|
||||
}
|
||||
|
||||
.content-right {
|
||||
width: 320px;
|
||||
flex-shrink: 0;
|
||||
}
|
||||
|
||||
/* 面板样式 */
|
||||
.info-panel,
|
||||
.form-panel,
|
||||
.history-panel,
|
||||
.approval-panel {
|
||||
background: white;
|
||||
border: 1px solid #e4e7ed;
|
||||
border-radius: 4px;
|
||||
overflow: hidden;
|
||||
}
|
||||
|
||||
.panel-header {
|
||||
background: #fafafa;
|
||||
border-bottom: 1px solid #e4e7ed;
|
||||
padding: 12px 16px;
|
||||
display: flex;
|
||||
justify-content: space-between;
|
||||
align-items: center;
|
||||
}
|
||||
|
||||
.panel-title {
|
||||
font-size: 14px;
|
||||
font-weight: 600;
|
||||
color: #303133;
|
||||
margin: 0;
|
||||
}
|
||||
|
||||
.panel-actions {
|
||||
display: flex;
|
||||
gap: 8px;
|
||||
}
|
||||
|
||||
.panel-content {
|
||||
padding: 16px;
|
||||
}
|
||||
|
||||
.panel-content.no-padding {
|
||||
padding: 0;
|
||||
}
|
||||
|
||||
/* 信息表格 */
|
||||
.info-table {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
gap: 12px;
|
||||
}
|
||||
|
||||
.info-row {
|
||||
display: flex;
|
||||
align-items: flex-start;
|
||||
gap: 12px;
|
||||
padding: 8px 0;
|
||||
border-bottom: 1px solid #f5f7fa;
|
||||
}
|
||||
|
||||
.info-row:last-child {
|
||||
border-bottom: none;
|
||||
}
|
||||
|
||||
.info-label {
|
||||
color: #606266;
|
||||
font-size: 14px;
|
||||
min-width: 80px;
|
||||
font-weight: 500;
|
||||
}
|
||||
|
||||
.info-value {
|
||||
color: #303133;
|
||||
font-size: 14px;
|
||||
flex: 1;
|
||||
line-height: 1.5;
|
||||
}
|
||||
|
||||
/* 表单内容 */
|
||||
.form-content {
|
||||
min-height: 200px;
|
||||
position: relative;
|
||||
}
|
||||
|
||||
/* 加载状态 */
|
||||
.loading-state {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
padding: 60px 20px;
|
||||
color: #909399;
|
||||
gap: 8px;
|
||||
}
|
||||
|
||||
.loading-state i {
|
||||
font-size: 20px;
|
||||
animation: spin 1s linear infinite;
|
||||
}
|
||||
|
||||
.loading-state span {
|
||||
font-size: 14px;
|
||||
}
|
||||
|
||||
@keyframes spin {
|
||||
from {
|
||||
transform: rotate(0deg);
|
||||
}
|
||||
to {
|
||||
transform: rotate(360deg);
|
||||
}
|
||||
}
|
||||
|
||||
/* 流程图查看器 */
|
||||
.diagram-viewer {
|
||||
height: 65vh;
|
||||
border: 1px solid #e4e7ed;
|
||||
border-radius: 4px;
|
||||
overflow: hidden;
|
||||
}
|
||||
|
||||
.diagram-viewer iframe {
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
}
|
||||
|
||||
/* 响应式设计 */
|
||||
@media (max-width: 1024px) {
|
||||
.main-content {
|
||||
flex-direction: column;
|
||||
}
|
||||
|
||||
.content-right {
|
||||
width: 100%;
|
||||
}
|
||||
}
|
||||
|
||||
@media (max-width: 768px) {
|
||||
.header-content {
|
||||
flex-direction: column;
|
||||
align-items: flex-start;
|
||||
gap: 8px;
|
||||
}
|
||||
|
||||
.main-content {
|
||||
padding: 16px;
|
||||
}
|
||||
|
||||
.panel-content {
|
||||
padding: 12px;
|
||||
}
|
||||
|
||||
.info-row {
|
||||
flex-direction: column;
|
||||
gap: 4px;
|
||||
}
|
||||
|
||||
.info-label {
|
||||
min-width: auto;
|
||||
}
|
||||
}
|
||||
</style>
|
||||
@@ -0,0 +1,380 @@
|
||||
<template>
|
||||
<div class="approval-sidebar">
|
||||
<div class="sidebar-header">
|
||||
<h4>审批记录</h4>
|
||||
</div>
|
||||
<div class="timeline-container" v-if="historyApprovalRecords.length > 0">
|
||||
<div class="timeline-wrapper">
|
||||
<div
|
||||
v-for="(record, index) in historyApprovalRecords"
|
||||
:key="record.id"
|
||||
class="timeline-item">
|
||||
|
||||
<!-- 时间线节点 -->
|
||||
<div class="timeline-node">
|
||||
<div class="timeline-dot" :class="getDotClass(record.taskState)"></div>
|
||||
<div class="timeline-line" v-if="index < historyApprovalRecords.length - 1"></div>
|
||||
</div>
|
||||
|
||||
<!-- 审批内容 -->
|
||||
<div class="timeline-content">
|
||||
<div class="approval-card">
|
||||
<div class="card-header">
|
||||
<span class="task-name">{{ record.displayName }}</span>
|
||||
<span class="approval-time">{{ formatTimestamp(record.finishTime || record.createdAt) }}</span>
|
||||
</div>
|
||||
|
||||
<div class="card-body">
|
||||
<div class="info-item" v-if="record.operator && record.operator !== 'flow.auto'">
|
||||
<span class="label">办理人:</span>
|
||||
<span class="value">{{ getOperatorName(record) }}</span>
|
||||
</div>
|
||||
|
||||
<div class="info-item" v-if="record.ext && record.ext.submitType">
|
||||
<span class="label">操作:</span>
|
||||
<span class="value submit-type" :class="'submit-' + record.ext.submitType">
|
||||
{{ getSubmitTypeText(record.ext.submitType) }}
|
||||
</span>
|
||||
</div>
|
||||
|
||||
<div class="info-item" v-if="record.ext && record.ext.opinion">
|
||||
<span class="label">意见:</span>
|
||||
<span class="value">{{ record.ext.opinion }}</span>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div v-else class="no-records">
|
||||
暂无审批记录
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
module.exports = {
|
||||
name: "SnakerFlowHisApproval",
|
||||
props: {
|
||||
task_id: {
|
||||
type: String | Number,
|
||||
required: true
|
||||
}
|
||||
},
|
||||
data() {
|
||||
return {
|
||||
// 历史审批记录
|
||||
historyApprovalRecords: [],
|
||||
|
||||
// 加载状态
|
||||
loading: false,
|
||||
|
||||
// 任务状态枚举
|
||||
taskStateEnum: {
|
||||
DOING: 10,
|
||||
FINISHED: 20,
|
||||
WITHDRAW: 30,
|
||||
INTERRUPT: 40,
|
||||
PENDING: 50,
|
||||
ABANDON: 99
|
||||
}
|
||||
}
|
||||
},
|
||||
computed: {
|
||||
// 获取实例ID(从task_id获取流程实例信息)
|
||||
instanceId() {
|
||||
return GetQueryString("instanceId")
|
||||
}
|
||||
},
|
||||
created() {
|
||||
this.loadHistoryApprovalRecords()
|
||||
},
|
||||
watch: {
|
||||
task_id: {
|
||||
handler(newVal) {
|
||||
if (newVal) {
|
||||
this.loadHistoryApprovalRecords()
|
||||
}
|
||||
},
|
||||
immediate: true
|
||||
}
|
||||
},
|
||||
methods: {
|
||||
// 加载历史审批记录
|
||||
async loadHistoryApprovalRecords() {
|
||||
if (!this.instanceId && !this.task_id) return
|
||||
|
||||
this.loading = true
|
||||
try {
|
||||
const params = this.instanceId ?
|
||||
{ instanceId: this.instanceId } :
|
||||
{ taskId: this.task_id }
|
||||
|
||||
const response = await $.post("/flow/common/approvalRecord", params)
|
||||
if (response.code === 0) {
|
||||
this.historyApprovalRecords = response.data || []
|
||||
}
|
||||
} catch (error) {
|
||||
console.error("加载历史审批记录失败:", error)
|
||||
} finally {
|
||||
this.loading = false
|
||||
}
|
||||
},
|
||||
|
||||
// 格式化时间戳
|
||||
formatTimestamp(timestamp) {
|
||||
if (!timestamp) return ""
|
||||
const date = new Date(timestamp)
|
||||
return date.toLocaleString("zh-CN", {
|
||||
month: "2-digit",
|
||||
day: "2-digit",
|
||||
hour: "2-digit",
|
||||
minute: "2-digit"
|
||||
})
|
||||
},
|
||||
|
||||
// 获取操作人姓名
|
||||
getOperatorName(record) {
|
||||
if (!record.operator || record.operator === 'flow.auto') {
|
||||
return "系统自动"
|
||||
}
|
||||
if (record.ext && record.ext.operatorName) {
|
||||
return record.ext.operatorName
|
||||
}
|
||||
return record.operator
|
||||
},
|
||||
|
||||
// 获取提交类型文本
|
||||
getSubmitTypeText(submitType) {
|
||||
const typeMap = {
|
||||
'agree': '同意',
|
||||
'reject': '拒绝',
|
||||
'back': '退回',
|
||||
'transfer': '转办',
|
||||
'delegate': '委托',
|
||||
'submit': '提交'
|
||||
}
|
||||
return typeMap[submitType] || submitType
|
||||
},
|
||||
|
||||
// 获取节点样式类
|
||||
getDotClass(state) {
|
||||
switch (state) {
|
||||
case this.taskStateEnum.FINISHED:
|
||||
return "dot-success"
|
||||
case this.taskStateEnum.WITHDRAW:
|
||||
return "dot-warning"
|
||||
case this.taskStateEnum.INTERRUPT:
|
||||
case this.taskStateEnum.ABANDON:
|
||||
return "dot-danger"
|
||||
case this.taskStateEnum.PENDING:
|
||||
return "dot-info"
|
||||
case this.taskStateEnum.DOING:
|
||||
return "dot-primary"
|
||||
default:
|
||||
return "dot-default"
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
||||
<style scoped>
|
||||
.approval-sidebar {
|
||||
width: 320px;
|
||||
background: #fff;
|
||||
border: 1px solid #ddd;
|
||||
height: fit-content;
|
||||
max-height: 80vh;
|
||||
overflow: hidden;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
}
|
||||
|
||||
.sidebar-header {
|
||||
background: #f5f5f5;
|
||||
border-bottom: 1px solid #ddd;
|
||||
padding: 12px 16px;
|
||||
flex-shrink: 0;
|
||||
}
|
||||
|
||||
.sidebar-header h4 {
|
||||
margin: 0;
|
||||
font-size: 14px;
|
||||
font-weight: normal;
|
||||
color: #333;
|
||||
}
|
||||
|
||||
.timeline-container {
|
||||
flex: 1;
|
||||
overflow-y: auto;
|
||||
padding: 16px;
|
||||
}
|
||||
|
||||
.timeline-wrapper {
|
||||
position: relative;
|
||||
}
|
||||
|
||||
.timeline-item {
|
||||
display: flex;
|
||||
margin-bottom: 20px;
|
||||
position: relative;
|
||||
}
|
||||
|
||||
.timeline-item:last-child {
|
||||
margin-bottom: 0;
|
||||
}
|
||||
|
||||
.timeline-node {
|
||||
position: relative;
|
||||
margin-right: 12px;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
align-items: center;
|
||||
}
|
||||
|
||||
.timeline-dot {
|
||||
width: 12px;
|
||||
height: 12px;
|
||||
border-radius: 50%;
|
||||
border: 2px solid #fff;
|
||||
position: relative;
|
||||
z-index: 2;
|
||||
}
|
||||
|
||||
.dot-success {
|
||||
background: #52c41a;
|
||||
}
|
||||
|
||||
.dot-warning {
|
||||
background: #faad14;
|
||||
}
|
||||
|
||||
.dot-danger {
|
||||
background: #f5222d;
|
||||
}
|
||||
|
||||
.dot-primary {
|
||||
background: #1890ff;
|
||||
}
|
||||
|
||||
.dot-info {
|
||||
background: #999;
|
||||
}
|
||||
|
||||
.dot-default {
|
||||
background: #d9d9d9;
|
||||
}
|
||||
|
||||
.timeline-line {
|
||||
width: 1px;
|
||||
background: #e8e8e8;
|
||||
flex: 1;
|
||||
margin-top: 4px;
|
||||
min-height: 30px;
|
||||
}
|
||||
|
||||
.timeline-content {
|
||||
flex: 1;
|
||||
min-width: 0;
|
||||
}
|
||||
|
||||
.approval-card {
|
||||
background: #fff;
|
||||
border: 1px solid #e8e8e8;
|
||||
border-radius: 2px;
|
||||
}
|
||||
|
||||
.card-header {
|
||||
background: #fafafa;
|
||||
border-bottom: 1px solid #e8e8e8;
|
||||
padding: 8px 12px;
|
||||
display: flex;
|
||||
justify-content: space-between;
|
||||
align-items: center;
|
||||
}
|
||||
|
||||
.task-name {
|
||||
font-size: 13px;
|
||||
font-weight: bold;
|
||||
color: #333;
|
||||
flex: 1;
|
||||
}
|
||||
|
||||
.approval-time {
|
||||
font-size: 12px;
|
||||
color: #999;
|
||||
}
|
||||
|
||||
.card-body {
|
||||
padding: 12px;
|
||||
}
|
||||
|
||||
.info-item {
|
||||
display: flex;
|
||||
margin-bottom: 6px;
|
||||
font-size: 12px;
|
||||
line-height: 1.5;
|
||||
}
|
||||
|
||||
.info-item:last-child {
|
||||
margin-bottom: 0;
|
||||
}
|
||||
|
||||
.label {
|
||||
color: #666;
|
||||
min-width: 50px;
|
||||
flex-shrink: 0;
|
||||
}
|
||||
|
||||
.value {
|
||||
color: #333;
|
||||
flex: 1;
|
||||
word-break: break-all;
|
||||
}
|
||||
|
||||
.submit-type {
|
||||
font-weight: bold;
|
||||
}
|
||||
|
||||
.submit-agree {
|
||||
color: #52c41a;
|
||||
}
|
||||
|
||||
.submit-reject {
|
||||
color: #f5222d;
|
||||
}
|
||||
|
||||
.submit-back {
|
||||
color: #faad14;
|
||||
}
|
||||
|
||||
.submit-transfer, .submit-delegate, .submit-submit {
|
||||
color: #1890ff;
|
||||
}
|
||||
|
||||
.no-records {
|
||||
padding: 40px 20px;
|
||||
text-align: center;
|
||||
color: #999;
|
||||
font-size: 14px;
|
||||
}
|
||||
|
||||
/* 滚动条样式 */
|
||||
.timeline-container::-webkit-scrollbar {
|
||||
width: 6px;
|
||||
}
|
||||
|
||||
.timeline-container::-webkit-scrollbar-track {
|
||||
background: #f1f1f1;
|
||||
}
|
||||
|
||||
.timeline-container::-webkit-scrollbar-thumb {
|
||||
background: #c1c1c1;
|
||||
}
|
||||
|
||||
.timeline-container::-webkit-scrollbar-thumb:hover {
|
||||
background: #a8a8a8;
|
||||
}
|
||||
</style>
|
||||
@@ -0,0 +1,226 @@
|
||||
<template>
|
||||
<div class="snaker-task-action" v-if="!loading || taskInfo">
|
||||
<!-- 第一个任务节点或新申请:显示提交、保存草稿、取消 -->
|
||||
<template v-if="isFirstTaskNodeOrNew">
|
||||
<el-button type="primary" @click="handleSubmit" :loading="actionLoading" icon="el-icon-upload2">提交</el-button>
|
||||
<!-- 保存草稿只在流程未发起时显示 -->
|
||||
<el-button @click="handleSaveDraft" v-if="!actionLoading && show_save_draft && !instanceId" icon="el-icon-document">保存草稿</el-button>
|
||||
<el-button @click="handleCancel" :loading="actionLoading" v-if="show_cancel" icon="el-icon-close">取消</el-button>
|
||||
</template>
|
||||
|
||||
<!-- 其他任务节点:显示审批按钮 -->
|
||||
<template v-else>
|
||||
<!-- 会签任务按钮 -->
|
||||
<template v-if="is_countersign_task">
|
||||
<el-button type="primary" @click="handleAction('AGREE')" :loading="actionLoading" icon="el-icon-check">同意</el-button>
|
||||
<el-button type="danger" plain @click="handleAction('COUNTERSIGN_DISAGREE')" :loading="actionLoading" icon="el-icon-close">
|
||||
不同意
|
||||
</el-button>
|
||||
</template>
|
||||
|
||||
<!-- 普通任务按钮 -->
|
||||
<template v-else>
|
||||
<el-button type="primary" @click="handleAction('AGREE')" :loading="actionLoading" icon="el-icon-check">同意</el-button>
|
||||
<el-button type="danger" plain @click="handleAction('REJECT')" :loading="actionLoading" icon="el-icon-close">拒绝</el-button>
|
||||
<el-button @click="handleAction('ROLLBACK')" :loading="actionLoading" icon="el-icon-back">退回上一步</el-button>
|
||||
<el-button @click="handleAction('ROLLBACK_TO_OPERATOR')" :loading="actionLoading" icon="el-icon-d-arrow-left">退回发起人</el-button>
|
||||
<el-button @click="handleAction('JUMP')" :loading="actionLoading" icon="el-icon-position">跳转</el-button>
|
||||
</template>
|
||||
</template>
|
||||
</div>
|
||||
|
||||
<!-- 加载状态 -->
|
||||
<div v-else class="snaker-task-action loading-state">
|
||||
<el-button loading icon="el-icon-loading">加载中...</el-button>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
module.exports = {
|
||||
name: "SnakerFlowTaskFormAction",
|
||||
props: {
|
||||
// 是否显示保存草稿按钮
|
||||
show_save_draft: {
|
||||
type: Boolean,
|
||||
default: true
|
||||
},
|
||||
// 是否显示取消按钮
|
||||
show_cancel: {
|
||||
type: Boolean,
|
||||
default: true
|
||||
}
|
||||
},
|
||||
data() {
|
||||
return {
|
||||
// 加载状态
|
||||
loading: false,
|
||||
// 操作按钮加载状态
|
||||
actionLoading: false,
|
||||
// 任务信息
|
||||
taskInfo: null,
|
||||
// 任务操作枚举
|
||||
actionEnum: {
|
||||
APPLY: "0", // 发起申请
|
||||
AGREE: "1", // 同意
|
||||
REJECT: "2", // 拒绝
|
||||
COUNTERSIGN_DISAGREE: "20", // 会签不同意 拒绝申请
|
||||
ROLLBACK: "3", // 退回上一步
|
||||
ROLLBACK_TO_OPERATOR: "6", // 退回发起人
|
||||
JUMP: "4", // 跳转
|
||||
RE_APPLY: "5", // 重新提交
|
||||
SUBMIT: "0" // 发起申请
|
||||
},
|
||||
// 任务类型枚举
|
||||
performTypeEnum: {
|
||||
NORMAL: 0, // 普通任务
|
||||
COUNTERSIGN: 1 // 会签任务
|
||||
},
|
||||
|
||||
taskId: GetQueryString("taskId"),
|
||||
instanceId: GetQueryString("instanceId"),
|
||||
defineKey: GetQueryString("defineKey"),
|
||||
defineId: GetQueryString("defineId"),
|
||||
businessId: GetQueryString("businessId")
|
||||
}
|
||||
},
|
||||
computed: {
|
||||
// 是否为会签任务
|
||||
is_countersign_task() {
|
||||
return this.taskInfo && this.taskInfo.performType === this.performTypeEnum.COUNTERSIGN
|
||||
},
|
||||
|
||||
// 是否为第一个任务节点或新申请
|
||||
isFirstTaskNodeOrNew() {
|
||||
// 没有任务ID,说明是新申请
|
||||
if (!this.taskId) {
|
||||
return true
|
||||
}
|
||||
|
||||
// 有任务ID但是任务信息中标识为第一个节点
|
||||
return this.taskInfo && this.taskInfo.ext && this.taskInfo.ext.isFirstTaskNode
|
||||
}
|
||||
},
|
||||
mounted() {
|
||||
// 只有当有任务ID时才加载任务信息
|
||||
if (this.taskId) {
|
||||
this.loadTaskInfo()
|
||||
}
|
||||
},
|
||||
methods: {
|
||||
// 加载任务信息
|
||||
loadTaskInfo() {
|
||||
if (!this.taskId) return
|
||||
|
||||
this.loading = true
|
||||
this.taskInfo = null
|
||||
|
||||
$.get("/flow/common/taskInfo", {
|
||||
taskId: this.taskId
|
||||
})
|
||||
.then((res) => {
|
||||
if (res.code === 0) {
|
||||
this.taskInfo = res.data
|
||||
}
|
||||
})
|
||||
.always(() => {
|
||||
this.loading = false
|
||||
})
|
||||
},
|
||||
|
||||
// 处理提交操作
|
||||
handleSubmit() {
|
||||
// 根据是否有流程实例来确定操作类型
|
||||
// const submitAction = this.instanceId ? this.actionEnum.RE_APPLY : this.actionEnum.APPLY
|
||||
const submitAction = this.actionEnum.APPLY
|
||||
|
||||
// 触发父组件事件,传递提交操作
|
||||
this.$emit("task-action", {
|
||||
submitType: submitAction,
|
||||
taskId: this.taskId,
|
||||
instanceId: this.instanceId,
|
||||
defineId: this.defineId,
|
||||
defineKey: this.defineKey,
|
||||
businessId: this.businessId
|
||||
// currentTask: this.taskInfo
|
||||
})
|
||||
},
|
||||
|
||||
// 处理任务操作
|
||||
handleAction(actionKey) {
|
||||
if (this.actionLoading || !this.taskInfo) return
|
||||
|
||||
// 触发父组件事件,传递操作类型和任务信息
|
||||
this.$emit("task-action", {
|
||||
submitType: this.actionEnum[actionKey],
|
||||
taskId: this.taskId,
|
||||
processTaskId: this.taskId,
|
||||
instanceId: this.instanceId,
|
||||
defineId: this.defineId,
|
||||
defineKey: this.defineKey,
|
||||
businessId: this.businessId
|
||||
})
|
||||
},
|
||||
|
||||
// 保存草稿
|
||||
handleSaveDraft() {
|
||||
if (this.actionLoading) return
|
||||
|
||||
// 保存草稿时不显示加载状态,因为只是保存业务数据
|
||||
this.$emit("save-draft", {
|
||||
defineId: this.defineId,
|
||||
businessId: this.businessId,
|
||||
isDraft: true // 标识这是草稿保存
|
||||
})
|
||||
},
|
||||
|
||||
// 取消操作
|
||||
handleCancel() {
|
||||
this.$emit("cancel")
|
||||
},
|
||||
|
||||
// 刷新任务信息
|
||||
refresh() {
|
||||
if (this.taskId) {
|
||||
this.loadTaskInfo()
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
||||
<style scoped>
|
||||
.snaker-task-action {
|
||||
text-align: center;
|
||||
padding: 20px;
|
||||
background: #fff;
|
||||
border-top: 1px solid #eee;
|
||||
margin-top: 20px;
|
||||
}
|
||||
|
||||
.snaker-task-action .el-button {
|
||||
margin: 0 8px;
|
||||
min-width: 80px;
|
||||
}
|
||||
|
||||
.loading-state {
|
||||
display: flex;
|
||||
justify-content: center;
|
||||
align-items: center;
|
||||
min-height: 60px;
|
||||
}
|
||||
|
||||
/* 响应式 */
|
||||
@media (max-width: 768px) {
|
||||
.snaker-task-action {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
gap: 10px;
|
||||
padding: 15px;
|
||||
}
|
||||
|
||||
.snaker-task-action .el-button {
|
||||
width: 100%;
|
||||
margin: 0;
|
||||
}
|
||||
}
|
||||
</style>
|
||||
@@ -0,0 +1,84 @@
|
||||
<template>
|
||||
<div>
|
||||
<template v-for="item in options">
|
||||
<el-tag :key="item[value_key]" v-if="item[value_key] === value" v-bind="$attrs">{{ item[label_key] }}</el-tag>
|
||||
</template>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
// 全局缓存和请求Promise缓存
|
||||
const enumCache = {}
|
||||
const requestPromises = {}
|
||||
|
||||
module.exports = {
|
||||
name: "DictTag",
|
||||
props: {
|
||||
value: { type: String | Number },
|
||||
name: { type: String },
|
||||
value_key: {
|
||||
type: String,
|
||||
default: "code"
|
||||
},
|
||||
label_key: {
|
||||
type: String,
|
||||
default: "name"
|
||||
}
|
||||
},
|
||||
data() {
|
||||
return {
|
||||
options: []
|
||||
}
|
||||
},
|
||||
watch: {
|
||||
code:{
|
||||
handler(val) {
|
||||
this.getEnumOptions()
|
||||
},
|
||||
immediate: true
|
||||
}
|
||||
},
|
||||
methods: {
|
||||
getEnumOptions() {
|
||||
// // 检查数据缓存
|
||||
// if (enumCache[this.name]) {
|
||||
// this.options = enumCache[this.name]
|
||||
// return
|
||||
// }
|
||||
//
|
||||
// // 检查是否已有相同请求在进行中
|
||||
// if (requestPromises[this.name]) {
|
||||
// requestPromises[this.name].then(data => {
|
||||
// this.options = data
|
||||
// })
|
||||
// return
|
||||
// }
|
||||
|
||||
// 创建请求Promise并缓存
|
||||
requestPromises[this.name] = $.get("/open/common/dictEnumOptions", { name: this.name })
|
||||
.then(res => {
|
||||
if (res.code === 0) {
|
||||
// 存入数据缓存
|
||||
enumCache[this.name] = res.data
|
||||
// 清除请求Promise缓存
|
||||
delete requestPromises[this.name]
|
||||
return res.data
|
||||
}
|
||||
})
|
||||
|
||||
requestPromises[this.name].then(data => {
|
||||
this.options = data
|
||||
})
|
||||
}
|
||||
},
|
||||
created() {
|
||||
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
||||
<style scoped>
|
||||
.el-tag + .el-tag {
|
||||
margin-left: 10px;
|
||||
}
|
||||
</style>
|
||||
Reference in New Issue
Block a user