feat: 数据同步 定时报告 优化

This commit is contained in:
dataeaseShu
2022-08-22 17:54:31 +08:00
parent 2067a1ed5e
commit fb0538954e
26 changed files with 3206 additions and 900 deletions

View File

@@ -61,8 +61,11 @@
</template>
<script>
import msgCfm from "@/components/msgCfm/index";
export default {
name: "TemplateList",
mixins: [msgCfm],
components: {},
props: {
templateType: {
@@ -119,22 +122,13 @@ export default {
this.$emit("showTemplateEditDialog", "new");
},
templateDelete(template) {
this.$alert(
this.$t("panel.confirm_delete") +
this.$t("panel.category") +
": " +
template.name +
"",
"",
{
confirmButtonText: this.$t("panel.confirm_delete"),
callback: (action) => {
if (action === "confirm") {
this.$emit("templateDelete", template.id);
}
},
}
);
const options = {
title: 'system_parameter_setting.delete_this_category',
content: 'system_parameter_setting.also_be_deleted',
type: "primary",
cb: () => this.$emit("templateDelete", template.id),
};
this.handlerConfirm(options);
},
templateEdit(template) {
this.$emit("templateEdit", template);

View File

@@ -208,29 +208,12 @@ export default {
}
},
templateDeleteConfirm(template) {
// const options = {
// title: 'jkjhjjhhkh',
// showCancelButton: false,
// type: 'primary',
// }
// this.handlerConfirm(options);
// return
this.$alert(
this.$t("panel.confirm_delete") +
this.$t("panel.template") +
": " +
this.template.name +
"",
"",
{
confirmButtonText: this.$t("panel.confirm"),
callback: (action) => {
if (action === "confirm") {
this.templateDelete(template.id);
}
},
}
);
const options = {
title: 'system_parameter_setting.delete_this_template',
type: "primary",
cb: () => this.templateDelete(template.id),
};
this.handlerConfirm(options);
},
handleClick(tab, event) {
this.getTree();
@@ -247,11 +230,7 @@ export default {
templateDelete(id) {
if (id) {
templateDelete(id).then((response) => {
this.$message({
message: this.$t("commons.delete_success"),
type: "success",
showClose: true,
});
this.openMessageSuccess('commons.delete_success');
this.getTree();
});
}

View File

@@ -258,9 +258,9 @@ export default {
z-index: 10;
}
.el-radio {
margin-right: 0;
width: 156px;
}
.el-radio:not(:last-child) {
margin-right: 0;
width: 156px;
}
}
</style>

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,268 @@
<template>
<el-dialog
:title="$t('chart.select_dataset')"
:visible.sync="selectDatasetFlag"
width="1200px"
class="de-dialog-form"
append-to-body
>
<div class="dataset-task-table">
<div class="dataset-tree">
<el-input
v-model="filterText"
size="mini"
:placeholder="$t('commons.search')"
prefix-icon="el-icon-search"
clearable
/>
<div class="tree" v-loading="treeLoading">
<el-tree
ref="datasetTreeRef"
current-node-key="id"
:data="treeData"
node-key="id"
highlight-current
:expand-on-click-node="true"
:filter-node-method="filterNode"
@node-click="nodeClick"
>
<span slot-scope="{ data }" class="custom-tree-node">
<span v-if="data.modelInnerType === 'group'">
<svg-icon icon-class="scene" class="ds-icon-scene" />
<span
style="
margin-left: 6px;
white-space: nowrap;
overflow: hidden;
text-overflow: ellipsis;
"
:title="data.name"
>{{ data.name }}</span
>
</span>
<span v-else>
<span>
<svg-icon
:icon-class="`ds-${data.modelInnerType}`"
:class="`ds-icon-${data.modelInnerType}`"
/>
</span>
<span
style="
margin-left: 6px;
white-space: nowrap;
overflow: hidden;
text-overflow: ellipsis;
"
:title="data.name"
>{{ data.name }}</span
>
</span>
</span>
</el-tree>
</div>
</div>
<div v-loading="dataLoading" class="dataset-tree-table">
<p v-if="tableName" class="table-name">
{{ tableName }} <span>{{ $t("chart.preview_100_data") }}</span>
</p>
<el-table border v-if="table.length" style="width: 100%" :data="table">
<el-table-column
v-for="field in fields"
:key="field.dataeaseName"
min-width="200"
:prop="field.dataeaseName"
:resizable="true"
>
<template slot="header">
<svg-icon
:icon-class="iconFormate(field.deType).iconClass"
:class="iconFormate(field.deType).class"
/>
<span>{{ field.name }}</span>
</template>
</el-table-column>
</el-table>
<el-empty v-else :description="$t('暂无数据')"></el-empty>
</div>
</div>
<div slot="footer" class="dialog-footer">
<deBtn secondary @click="selectDatasetFlag = false">{{
$t("chart.cancel")
}}</deBtn>
<deBtn @click="setIdName" :disabled="!tableName" type="primary">{{
$t("fu.table.ok")
}}</deBtn>
</div>
</el-dialog>
</template>
<script>
import { queryAuthModel } from "@/api/authModel/authModel";
import { post } from "@/api/dataset/dataset";
export default {
props: {
customType: {
type: Array,
required: false,
default: null,
},
mode: {
type: Number,
required: false,
default: -1,
},
privileges: {
type: String,
required: false,
default: "use",
},
clearEmptyDir: {
type: Boolean,
required: false,
default: false,
},
},
watch: {
filterText(val) {
this.$refs.datasetTreeRef.filter(val);
},
},
data() {
return {
selectDatasetFlag: false,
tableName: "",
tableId: "",
treeData: [],
table: [],
filterText: "",
fields: [],
tableName: "",
dataLoading: false,
treeLoading: false,
};
},
mounted() {
this.treeNode();
},
methods: {
iconFormate(deType) {
const val = ["text", "time", "value", "value", "location"][deType];
return {
class: `field-icon-${val}`,
iconClass: `field_${val}`,
};
},
treeNode() {
this.treeLoading = true;
const modelInnerTypeArray = Array.isArray(this.customType)
? [...this.customType, "group"]
: null;
queryAuthModel(
{
modelType: "dataset",
privileges: this.privileges,
datasetMode: this.mode,
clearEmptyDir: this.clearEmptyDir,
mode: this.mode < 0 ? null : this.mode,
modelInnerTypeArray,
},
true
)
.then((res) => {
this.treeData = res.data;
})
.finally(() => {
this.treeLoading = false;
});
},
filterNode(value, data) {
if (!value) return true;
return data.label.indexOf(value) !== -1;
},
initData(table) {
this.dataLoading = true;
table.row = 100;
post("/dataset/table/getPreviewData/1/100", table, false, 30000)
.then((response) => {
this.fields = response.data.fields;
this.table = response.data.data;
})
.finally((res) => {
this.dataLoading = false;
});
},
init() {
this.tableName = "";
this.tableId = "";
this.selectDatasetFlag = true;
},
setIdName() {
this.$emit("getTableId", this.tableId, this.tableName);
this.selectDatasetFlag = false;
},
nodeClick(data) {
const { id, name, modelInnerType: type } = data;
if (type === "group") return;
this.tableName = name;
this.tableId = id;
this.initData(data);
},
},
};
</script>
<style lang="scss">
.dataset-task-table {
box-sizing: border-box;
height: 628px;
border: 1px solid #dee0e3;
border-radius: 4px;
display: flex;
max-height: 628px;
.el-tree-node__content {
height: 40px;
border-radius: 4px;
&:hover {
background-color: var(--deWhiteHover, #3370ff) !important;
.custom-tree-node {
color: var(--primary, #3370ff);
}
}
}
.dataset-tree {
width: 253px;
border-right: 1px solid #dee0e3;
padding: 16px;
.tree {
padding-top: 16px;
overflow-y: auto;
height: calc(100% - 30px);
}
}
.dataset-tree-table {
flex: 1;
padding: 16px;
overflow-y: auto;
.table-name {
margin: 0;
margin-bottom: 16px;
display: flex;
align-items: center;
justify-content: space-between;
font-family: PingFang SC;
font-size: 16px;
font-weight: 500;
line-height: 24px;
color: var(--deTextPrimary, #000000);
span {
font-size: 14px;
font-weight: 400;
color: #646a73;
}
}
}
}
</style>

View File

@@ -1,8 +1,66 @@
<template>
<el-col>
<el-row v-loading="$store.getters.loadingMap[$store.getters.currentPath]" style="margin-top: 10px;">
<complex-table :data="data" :columns="columns" local-key="datasetTaskRecord" :search-config="searchConfig" :trans-condition="transCondition" :pagination-config="paginationConfig" @select="select" @search="search" @sort-change="sortChange">
<el-table-column prop="name" :label="$t('dataset.task_name')">
<div class="dataset-on-time">
<el-row class="top-operate">
<el-col :span="10">
<deBtn
secondary
>{{ $t("zip.export") }}</deBtn
>
</el-col>
<el-col :span="14" class="right-user">
<el-input
:placeholder="$t('通过任务名称搜索')"
prefix-icon="el-icon-search"
class="name-email-search"
size="small"
clearable
ref="search"
v-model="nikeName"
@blur="initSearch"
@clear="initSearch"
>
</el-input>
<deBtn
:secondary="!cacheCondition.length"
:plain="!!cacheCondition.length"
icon="iconfont icon-icon-filter"
@click="filterShow"
>{{ $t("user.filter")
}}<template v-if="filterTexts.length">
({{ cacheCondition.length }})
</template>
</deBtn>
</el-col>
</el-row>
<div class="filter-texts" v-if="filterTexts.length">
<span class="sum">{{ paginationConfig.total }}</span>
<span class="title">{{$t('user.result_one')}}</span>
<el-divider direction="vertical"></el-divider>
<i @click="scrollPre" v-if="showScroll" class="el-icon-arrow-left arrow-filter"></i>
<div class="filter-texts-container">
<p class="text" v-for="(ele, index) in filterTexts" :key="ele">
{{ ele }} <i @click="clearOneFilter(index)" class="el-icon-close"></i>
</p>
</div>
<i @click="scrollNext" v-if="showScroll" class="el-icon-arrow-right arrow-filter"></i>
<el-button
type="text"
class="clear-btn"
icon="el-icon-delete"
@click="clearFilter"
>{{$t('user.clear_filter')}}</el-button
>
</div>
<div id="resize-for-filter" class="table-container">
<grid-table
v-loading="$store.getters.loadingMap[$store.getters.currentPath]"
:tableData="data"
:columns="[]"
:pagination="paginationConfig"
@size-change="handleSizeChange"
@current-change="handleCurrentChange"
>
<el-table-column prop="name" :label="$t('dataset.task_name')">
<template slot-scope="scope">
<span>
<el-link :type="matchLogId && scope.row.id === matchLogId ? 'danger': ''" style="font-size: 12px" @click="jumpTask(scope.row)">{{ scope.row.name }}</el-link>
@@ -23,44 +81,48 @@
<el-table-column prop="status" :label="$t('dataset.status')">
<template slot-scope="scope">
<span v-if="scope.row.status === 'Completed'" style="color: green">{{ $t('dataset.completed') }}</span>
<span v-if="scope.row.status === 'Underway'" class="blue-color">
<i class="el-icon-loading" />
{{ $t('dataset.underway') }}
</span>
<span v-if="scope.row.status === 'Error'" style="color: red">
<el-link type="danger" style="font-size: 12px" @click="showErrorMassage(scope.row.info)">{{ $t('dataset.error') }}</el-link>
<span :class="[`de-${scope.row.status}`, 'de-status']"
>{{
$t(`dataset.${scope.row.status.toLocaleLowerCase()}`)
}}
<i
v-if="scope.row.status === 'Error'"
class="el-icon-question"
@click="showErrorMassage(scope.row.msg)"
></i>
</span>
</template>
</el-table-column>
</complex-table>
</el-row>
</grid-table>
<keep-alive>
<filterUser ref="filterUser" @search="filterDraw"></filterUser>
</keep-alive>
</div>
<el-dialog
v-dialogDrag
:title="$t('dataset.detail')"
:visible="show_error_massage"
:show-close="false"
width="50%"
class="dialog-css"
:title="$t('dataset.error') + $t('dataset.detail')"
:visible.sync="show_error_massage"
width="600px"
class="de-dialog-form"
>
<span class="err-msg">{{ error_massage }}</span>
<span slot="footer" class="dialog-footer">
<el-button size="mini" @click="show_error_massage = false">{{ $t('dataset.close') }}</el-button>
<deBtn secondary @click="show_error_massage = false">{{ $t('dataset.close') }}</deBtn>
</span>
</el-dialog>
</el-col>
</div>
</template>
<script>
import ComplexTable from '@/components/business/complex-table'
import { formatCondition, formatQuickCondition, addOrder, formatOrders } from '@/utils/index'
import '@riophae/vue-treeselect/dist/vue-treeselect.css'
import { formatOrders } from '@/utils/index'
import { post } from '@/api/dataset/dataset'
import { loadMenus } from '@/permission'
import GridTable from "@/components/gridTable/index.vue";
import filterUser from "./filterUserRecord.vue";
import _ from 'lodash';
export default {
name: 'TaskRecord',
components: { ComplexTable },
components: { GridTable, filterUser },
props: {
param: {
type: Object,
@@ -73,48 +135,18 @@ export default {
},
data() {
return {
header: '',
columns: [],
buttons: [
{
label: this.$t('commons.edit'), icon: 'el-icon-edit', type: 'primary', click: this.edit,
show: this.checkPermission(['user:edit'])
}
],
searchConfig: {
useQuickSearch: true,
useComplexSearch: true,
quickPlaceholder: this.$t('dataset.task.search_by_name'),
components: [
{ field: 'dataset_table_task.name', label: this.$t('dataset.task_name'), component: 'FuComplexInput' },
{ field: 'dataset_table_task.id', label: this.$t('dataset.task_id'), component: 'FuComplexInput' },
{ field: 'dataset_table.name', label: this.$t('dataset.name'), component: 'DeComplexInput' },
{ field: 'dataset_table_task_log.status', label: this.$t('commons.status'), component: 'FuComplexSelect', options: [{ label: this.$t('dataset.completed'), value: 'Completed' }, { label: this.$t('dataset.underway'), value: 'Underway' }, { label: this.$t('dataset.error'), value: 'Error' }], multiple: false }
]
},
nikeName: '',
showScroll: false,
filterTexts: [],
cacheCondition: [],
paginationConfig: {
currentPage: 1,
pageSize: 10,
total: 0
},
data: [],
dialogVisible: false,
editPasswordVisible: false,
form: {
roles: [{
id: ''
}]
},
checkPasswordForm: {},
ruleForm: {},
defaultForm: { id: null, username: null, nickName: null, gender: '男', email: null, enabled: 1, deptId: null, phone: null },
depts: null,
roles: [],
roleDatas: [],
userRoles: [],
formType: 'add',
orderConditions: [],
last_condition: null,
show_error_massage: false,
error_massage: '',
matchLogId: null,
@@ -133,14 +165,72 @@ export default {
}
this.createTimer()
},
mounted() {
this.resizeObserver();
},
watch: {
filterTexts: {
handler() {
this.getScrollStatus();
},
deep: true,
},
},
beforeDestroy() {
this.destroyTimer()
},
methods: {
getScrollStatus() {
this.$nextTick(() => {
const dom = document.querySelector(".filter-texts-container");
this.showScroll = dom && dom.scrollWidth > dom.offsetWidth;
});
},
resizeObserver() {
this.resizeForFilter = new ResizeObserver(entries => {
if (!this.filterTexts.length) return;
this.layoutResize();
});
this.resizeForFilter.observe(document.querySelector('#resize-for-filter'));
},
layoutResize: _.debounce(function () {
this.getScrollStatus()
}, 200),
scrollPre() {
const dom = document.querySelector('.filter-texts-container');
dom.scrollLeft -= 10
if (dom.scrollLeft <= 0) {
dom.scrollLeft = 0
}
},
scrollNext() {
const dom = document.querySelector('.filter-texts-container');
dom.scrollLeft += 10
const width = dom.scrollWidth - dom.offsetWidth
if (dom.scrollLeft > width) {
dom.scrollLeft = width
}
},
clearFilter() {
this.$refs.filterUser.clearFilter();
},
clearOneFilter(index) {
this.$refs.filterUser.clearOneFilter(index);
this.$refs.filterUser.search();
},
filterDraw(condition, filterTexts = []) {
this.cacheCondition = condition;
this.filterTexts = filterTexts;
this.initSearch();
},
filterShow() {
this.$refs.filterUser.init();
},
createTimer() {
this.initSearch();
if (!this.timer) {
this.timer = setInterval(() => {
this.timerSearch(this.last_condition, false)
this.timerSearch(false)
}, 15000)
}
},
@@ -150,36 +240,36 @@ export default {
this.timer = null
}
},
sortChange({ column, prop, order }) {
this.orderConditions = []
if (!order) {
this.search(this.last_condition)
return
}
if (prop === 'dept') {
prop = 'u.deptId'
}
if (prop === 'status') {
prop = 'u.enabled'
}
this.orderConditions = []
addOrder({ field: prop, value: order }, this.orderConditions)
this.search(this.last_condition)
handleSizeChange(pageSize) {
this.paginationConfig.currentPage = 1;
this.paginationConfig.pageSize = pageSize;
this.search();
},
select(selection) {
handleCurrentChange(currentPage) {
this.paginationConfig.currentPage = currentPage;
this.search();
},
timerSearch(condition, showLoading = true) {
initSearch() {
this.handleCurrentChange(1);
},
timerSearch(showLoading = true) {
if (!this.lastRequestComplete) {
return
} else {
this.lastRequestComplete = false
}
this.last_condition = condition
condition = formatQuickCondition(condition, 'dataset_table_task.name')
const temp = formatCondition(condition)
const param = temp || {}
param['orders'] = formatOrders(this.orderConditions)
const param = {
orders: formatOrders(this.orderConditions),
conditions: [...this.cacheCondition],
};
if (this.nikeName) {
param.conditions.push({
field: `dataset_table_task.name`,
operator: "like",
value: this.nikeName,
});
}
post('/dataset/taskLog/list/notexcel/' + this.paginationConfig.currentPage + '/' + this.paginationConfig.pageSize, param, showLoading).then(response => {
this.data = response.data.listObject
this.paginationConfig.total = response.data.itemCount
@@ -189,11 +279,17 @@ export default {
})
},
search(condition, showLoading = true) {
this.last_condition = condition
condition = formatQuickCondition(condition, 'dataset_table_task.name')
const temp = formatCondition(condition)
const param = temp || {}
param['orders'] = formatOrders(this.orderConditions)
const param = {
orders: formatOrders(this.orderConditions),
conditions: [...this.cacheCondition],
};
if (this.nikeName) {
param.conditions.push({
field: `dataset_table_task.name`,
operator: "like",
value: this.nikeName,
});
}
post('/dataset/taskLog/list/notexcel/' + this.paginationConfig.currentPage + '/' + this.paginationConfig.pageSize, param, showLoading).then(response => {
this.data = response.data.listObject
this.paginationConfig.total = response.data.itemCount
@@ -255,3 +351,202 @@ span{
}
</style>
<style lang="scss" scoped>
.dataset-on-time {
margin: 0;
width: 100%;
overflow: auto;
background-color: var(--ContentBG, #fff);
padding: 24px;
height: 100%;
}
.table-container {
height: calc(100% - 50px);
.text-btn {
font-family: PingFang SC;
font-size: 14px;
font-weight: 400;
line-height: 22px;
letter-spacing: 0px;
text-align: center;
margin-left: 2px;
border: none;
padding: 2px 4px;
}
.text-btn:hover {
background: rgba(51, 112, 255, 0.1);
}
.mar6 {
margin-right: 6px;
}
.mar3 {
margin-left: -3px;
}
}
.table-container-filter {
height: calc(100% - 110px);
}
.filter-texts {
display: flex;
align-items: center;
margin: 17px 0;
font-family: "PingFang SC";
font-weight: 400;
.sum {
color: #1f2329;
}
.title {
color: #999999;
margin-left: 8px;
}
.text {
max-width: 280px;
overflow: hidden;
text-overflow: ellipsis;
white-space: nowrap;
padding: 1px 22px 1px 6px;
display: inline-block;
align-items: center;
color: #0c296e;
font-size: 14px;
line-height: 22px;
background: rgba(51, 112, 255, 0.1);
border-radius: 2px;
margin: 0;
margin-right: 8px;
position: relative;
i {
position: absolute;
right: 2px;
top: 50%;
transform: translateY(-50%);
cursor: pointer;
}
}
.clear-btn {
color: #646a73;
}
.clear-btn:hover {
color: #3370ff;
}
.filter-texts-container::-webkit-scrollbar { display: none; }
.arrow-filter {
font-size: 16px;
width: 24px;
height: 24px;
cursor: pointer;
color: #646A73;
display: flex;
justify-content: center;
align-items: center;
}
.arrow-filter:hover {
background: rgba(31, 35, 41, 0.1);
border-radius: 4px;
}
.el-icon-arrow-right.arrow-filter {
margin-left: 5px;
}
.el-icon-arrow-left.arrow-filter {
margin-right: 5px;
}
.filter-texts-container {
flex: 1;
overflow-x: auto;
white-space: nowrap;
height: 24px;
}
}
.top-operate {
margin-bottom: 16px;
.right-user {
text-align: right;
display: flex;
align-items: center;
justify-content: flex-end;
.de-button {
margin-left: 12px;
}
.el-input--medium .el-input__icon {
line-height: 32px;
}
}
.name-email-search {
width: 240px;
}
}
</style>
<style lang="scss">
.de-status {
position: relative;
margin-left: 15px;
&::before {
content: "";
position: absolute;
top: 50%;
left: -13px;
transform: translateY(-50%);
width: 5px;
height: 5px;
border-radius: 50%;
}
}
.de-Completed {
&::before {
background: var(--primary, #3370ff);
}
}
.de-Underway {
&::before {
background: #8f959e;
}
}
.de-Pending {
&::before {
background: #8f959e;
}
}
.de-Exec {
&::before {
background: var(--primary, #3370ff);
}
}
.de-Stopped {
&::before {
background: var(--deSuccess, #3370ff);
}
}
.de-Error {
&::before {
background: var(--deDanger, #3370ff);
}
.el-icon-question {
color: #646A73;
cursor: pointer;
}
}
</style>

View File

@@ -1,113 +1,123 @@
<template>
<layout-content>
<el-row>
<de-layout-content>
<div class="organization">
<el-tabs v-model="tabActive" @tab-click="changeTab">
<el-tab-pane :label="$t('dataset.task.list')" name="DatasetTaskList">
<dataset-task-list v-if="tabActive=='DatasetTaskList'" :param="task" :trans-condition="transCondition" @jumpTaskRecord="jumpTaskRecord" />
</el-tab-pane>
<el-tab-pane :label="$t('dataset.task.record')" name="TaskRecord">
<task-record v-if="tabActive=='TaskRecord'" ref="task_record" :param="task" :trans-condition="transCondition" @jumpTask="jumpTask" />
</el-tab-pane>
</el-tabs>
</el-row>
</layout-content>
<div class="tabs-container">
<dataset-task-list
v-if="tabActive == 'DatasetTaskList'"
:param="task"
:trans-condition="transCondition"
@jumpTaskRecord="jumpTaskRecord"
/>
<task-record
v-if="tabActive == 'TaskRecord'"
ref="task_record"
:param="task"
:trans-condition="transCondition"
@jumpTask="jumpTask"
/>
</div>
</div>
</de-layout-content>
</template>
<script>
import DeLayoutContent from "@/components/business/DeLayoutContent";
import LayoutContent from '@/components/business/LayoutContent'
import DatasetTaskList from "@/views/system/task/DatasetTaskList";
import TaskRecord from "@/views/system/task/TaskRecord";
import DatasetTaskList from '@/views/system/task/DatasetTaskList'
import TaskRecord from '@/views/system/task/TaskRecord'
import bus from '@/utils/bus'
import { mapGetters } from 'vuex'
import bus from "@/utils/bus";
import { mapGetters } from "vuex";
export default {
components: { LayoutContent, DatasetTaskList, TaskRecord },
components: { DeLayoutContent, DatasetTaskList, TaskRecord },
data() {
return {
tabActive: 'DatasetTaskList',
tabActive: "DatasetTaskList",
transCondition: {},
task: null
}
task: null,
};
},
computed: {
...mapGetters([
'permission_routes'
])
...mapGetters(["permission_routes"]),
},
mounted() {
bus.$on('to-msg-dataset', this.toMsgShare)
bus.$on("to-msg-dataset", this.toMsgShare);
},
beforeDestroy() {
bus.$off('to-msg-dataset', this.toMsgShare)
bus.$off("to-msg-dataset", this.toMsgShare);
},
created() {
this.$store.dispatch('app/toggleSideBarHide', false)
const routerParam = this.$router.currentRoute.params
routerParam && this.$nextTick(() => {
this.toMsgShare(routerParam)
})
this.$store.dispatch("app/toggleSideBarHide", false);
const routerParam = this.$router.currentRoute.params;
routerParam &&
this.$nextTick(() => {
this.toMsgShare(routerParam);
});
},
methods: {
changeTab() {
this.task = null
this.transCondition = {}
this.task = null;
this.transCondition = {};
},
jumpTaskRecord(task) {
this.transCondition['dataset_table_task.id'] = {
operator: 'eq',
value: task.id
}
this.tabActive = 'TaskRecord'
this.transCondition["dataset_table_task.id"] = {
operator: "eq",
value: task.id,
};
this.tabActive = "TaskRecord";
},
jumpTask(taskRecord) {
this.transCondition['dataset_table_task.id'] = {
operator: 'eq',
value: taskRecord.taskId
}
this.tabActive = 'DatasetTaskList'
this.transCondition["dataset_table_task.id"] = {
operator: "eq",
value: taskRecord.taskId,
};
this.tabActive = "DatasetTaskList";
},
toMsgShare(routerParam) {
if (routerParam !== null && routerParam.msgNotification) {
const panelShareTypeIds = [4, 5, 6]
const panelShareTypeIds = [4, 5, 6];
// 说明是从消息通知跳转过来的
if (panelShareTypeIds.includes(routerParam.msgType)) { // 是数据集同步
if (panelShareTypeIds.includes(routerParam.msgType)) {
// 是数据集同步
if (routerParam.sourceParam) {
this.openSystem()
this.openSystem();
try {
const msgParam = JSON.parse(routerParam.sourceParam)
const msgParam = JSON.parse(routerParam.sourceParam);
// this.param = msgParam.tableId
this.$nextTick(() => {
// 目标组件存在定时器 这种方式会被定时器阻塞
// this.$refs.task_record && this.$refs.task_record.msg2Current && this.$refs.task_record.msg2Current(msgParam)
this.task = msgParam
this.tabActive = 'TaskRecord'
})
this.task = msgParam;
this.tabActive = "TaskRecord";
});
} catch (error) {
console.error(error)
console.error(error);
}
}
}
}
},
openSystem() {
const path = '/system'
const path = "/system";
let route = this.permission_routes.find(
item => item.path === '/' + path.split('/')[1]
)
(item) => item.path === "/" + path.split("/")[1]
);
// 如果找不到这个路由,说明是首页
if (!route) {
route = this.permission_routes.find(item => item.path === '/')
route = this.permission_routes.find((item) => item.path === "/");
}
this.$store.commit('permission/SET_CURRENT_ROUTES', route)
this.$store.commit("permission/SET_CURRENT_ROUTES", route);
// this.setSidebarHide(route)
}
}
}
},
},
};
</script>
<style lang="scss" scoped>
@@ -119,7 +129,7 @@ export default {
padding: 10px 10px;
}
::v-deep .el-radio-button__orig-radio:checked+.el-radio-button__inner {
::v-deep .el-radio-button__orig-radio:checked + .el-radio-button__inner {
color: #fff;
background-color: #0a7be0;
border-color: #0a7be0;
@@ -128,10 +138,32 @@ export default {
}
}
.de-msg-a:hover {
text-decoration: underline !important;
color: #0a7be0 !important;
cursor: pointer !important;
text-decoration: underline !important;
color: #0a7be0 !important;
cursor: pointer !important;
}
</style>
<style scoped lang="scss">
.organization {
height: 100%;
background-color: var(--MainBG, #f5f6f7);
.tabs-container {
height: calc(100% - 48px);
background: var(--ContentBG, #ffffff);
overflow-x: auto;
}
>>> .el-tabs__header {
margin: 0 0 12px;
}
>>> .el-tabs__item {
height: 24px;
line-height: 24px;
margin-bottom: 9px;
padding: 0 12px;
font-size: 16px;
}
}
</style>

View File

@@ -0,0 +1,466 @@
<template>
<el-drawer
:title="$t('user.filter_method')"
:visible.sync="userDrawer"
custom-class="user-drawer"
size="680px"
v-closePress
direction="rtl"
>
<div class="filter">
<span>{{ $t("dataset.datalist") }}</span>
<div class="filter-item">
<span
class="item"
@click="activeDatasetChange(ele.id)"
:class="[activeDataset.includes(ele.id) ? 'active' : '']"
:key="ele.id"
v-for="ele in selectDatasetsCahe"
>{{ ele.name }}</span
>
<el-popover
placement="bottom"
popper-class="user-popper"
width="200"
trigger="click"
>
<el-popover
placement="bottom"
popper-class="user-popper dept"
width="200"
trigger="click"
v-loading="treeLoading"
>
<el-tree
ref="datasetTreeRef"
current-node-key="id"
:data="treeData"
node-key="id"
highlight-current
:filter-node-method="filterNode"
:expand-on-click-node="true"
@node-click="nodeClick"
>
<span slot-scope="{ data }" class="custom-tree-node">
<span v-if="data.modelInnerType === 'group'">
<svg-icon icon-class="scene" class="ds-icon-scene" />
<span
style="
margin-left: 6px;
white-space: nowrap;
overflow: hidden;
text-overflow: ellipsis;
"
:title="data.name"
>{{ data.name }}</span
>
</span>
<span v-else>
<span>
<svg-icon
:icon-class="`ds-${data.modelInnerType}`"
:class="`ds-icon-${data.modelInnerType}`"
/>
</span>
<span
style="
margin-left: 6px;
white-space: nowrap;
overflow: hidden;
text-overflow: ellipsis;
"
:title="data.name"
>{{ data.name }}</span
>
</span>
</span>
</el-tree>
<el-select
ref="datasetSelect"
v-model="selectDatasets"
slot="reference"
popper-class="tree-select"
multiple
:placeholder="$t('commons.please_select')"
value-key="id"
>
<el-option
v-for="item in selectDatasets"
:key="item.name"
:label="item.name"
:value="item"
/>
</el-select>
</el-popover>
<span class="more" slot="reference">+ {{ $t("panel.more") }}</span>
</el-popover>
</div>
</div>
<div v-for="ele in filterDataset" :key="ele.name" class="filter">
<span>{{ $t(ele.name) }}</span>
<div class="filter-item">
<span
class="item"
@click="statusChange(item.value, ele.activeType)"
:class="[active[ele.activeType].includes(item.value) ? 'active' : '']"
:key="item.name"
v-for="item in ele.list"
>{{ $t(item.name) }}</span
>
</div>
</div>
<div class="filter">
<span>{{ $t("dedaterange.label") }}</span>
<div class="filter-item">
<el-date-picker
v-model="dataRange"
size="small"
type="daterange"
range-separator=""
start-placeholder="开始日期"
end-placeholder="结束日期"
>
</el-date-picker>
</div>
</div>
<div class="foot">
<el-button class="btn normal" @click="reset">{{
$t("commons.reset")
}}</el-button>
<el-button type="primary" class="btn" @click="search">{{
$t("commons.adv_search.search")
}}</el-button>
</div>
</el-drawer>
</template>
<script>
import { filterDataset, dateFormat } from "./options";
import { allRoles } from "@/api/system/user";
import { getDatasetTree, treeByDatasetId } from "@/api/system/dept";
import { queryAuthModel } from "@/api/authModel/authModel";
export default {
data() {
return {
treeLoading: false,
dataRange: [],
selectDatasets: [],
datasetCahe: [],
activeDataset: [],
selectDatasetsCahe: [],
treeData: [],
filterDataset,
active: {
execStatus: [],
status: [],
rate: [],
},
userDrawer: false,
};
},
mounted() {
this.treeNode();
},
methods: {
treeNode() {
this.treeLoading = true;
queryAuthModel(
{
modelType: "dataset",
privileges: "manage",
datasetMode: 1,
clearEmptyDir: true,
mode: 1,
modelInnerTypeArray: ["db", "sql", "api", "group"],
},
true
)
.then((res) => {
this.treeData = res.data;
})
.finally(() => {
this.treeLoading = false;
});
},
nodeClick(data) {
const { id, name, modelInnerType: type } = data;
if (type === "group") return;
this.handleNodeClick(id, name);
},
filterNode(value, data) {
if (!value) return true;
return !this.activeDataset.includes(data.id);
},
clearFilter() {
this.active = {
execStatus: [],
status: [],
rate: [],
};
this.dataRange = [];
this.activeDataset = [];
this.selectDatasets = [];
this.datasetCahe = [];
this.selectDatasetsCahe = [];
this.$emit("search", [], []);
},
clearOneFilter(index) {
(this.filterTextMap[index] || []).forEach((ele) => {
const eleKey = ele.split(".");
if (eleKey.length === 2) {
const [p, c] = eleKey;
this[p][c] = [];
} else {
this[ele] = [];
}
});
},
statusChange(value, type) {
const statusIndex = this.active[type].findIndex((ele) => ele === value);
if (statusIndex === -1) {
this.active[type].push(value);
} else {
this.active[type].splice(statusIndex, 1);
}
},
handleNodeClick(id, name) {
const datasetIdx = this.selectDatasets.findIndex((ele) => ele.id === id);
if (datasetIdx !== -1) {
this.selectDatasets.splice(datasetIdx, 1);
this.selectDatasetsCahe = this.selectDatasetsCahe.filter(
(ele) => ele.id !== id
);
this.datasetCahe = this.datasetCahe.filter((ele) => ele.id !== id);
this.$refs.datasetTreeRef.filter(id);
return;
}
this.activeDataset.push(id);
this.selectDatasetsCahe.push({ id, name });
this.datasetCahe.push({ id, name });
this.$refs.datasetTreeRef.filter(id);
},
activeDatasetChange(id) {
const dataset = this.datasetCahe.find((ele) => ele.id === id);
this.selectDatasets.push(dataset);
this.activeDataset = this.activeDataset.filter((ele) => ele !== id);
this.selectDatasetsCahe = this.selectDatasetsCahe.filter(
(ele) => ele.id !== id
);
},
search() {
this.userDrawer = false;
this.$emit("search", this.formatCondition(), this.formatText());
},
formatText() {
this.filterTextMap = [];
const params = [];
if (this.activeDataset.length) {
let str = `${this.$t("dataset.datalist")}:${this.activeDataset.reduce(
(pre, next) =>
(this.datasetCahe.find((ele) => ele.id === next) || {}).name +
"、" +
pre,
""
)}`;
params.push(str.slice(0, str.length - 1));
this.filterTextMap.push([
"activeDataset",
"selectDatasets",
"selectDatasetsCahe",
"datasetCahe",
]);
}
[
"dataset.execute_rate",
"dataset.task.task_status",
"dataset.task.last_exec_status",
].forEach((ele, index) => {
const { activeType: type, list } =
filterDataset[index];
if (this.active[type].length) {
params.push(
`${this.$t(ele)}:${this.active[type]
.map((item) => this.$t(list.find((itx) => itx.value === item).name))
.join("、")}`
);
this.filterTextMap.push([`active.${type}`]);
}
});
if (this.dataRange.length) {
params.push(
`${this.$t("dedaterange.label")}:${this.dataRange
.map((ele) => {
return dateFormat("YYYY-mm-dd", ele);
})
.join("-")}`
);
this.filterTextMap.push(["dataRange"]);
}
return params;
},
formatCondition() {
const fildMap = {
"dataset_table_task.rate": this.active.rate,
"dataset_table_task.status": this.active.status,
"dataset_table_task.last_exec_status": this.active.execStatus,
"dataset_table.id": this.activeDataset,
};
const conditions = [];
Object.keys(fildMap).forEach((ele) => {
if (fildMap[ele].length) {
conditions.push({
field: ele,
operator: "in",
value: fildMap[ele],
});
}
});
const [min, max] = this.dataRange;
if (min && max) {
conditions.push({
field: "dataset_table_task.last_exec_time",
operator: "between",
value: [+min, +max],
});
}
return conditions;
},
init() {
this.userDrawer = true;
},
reset() {
this.clearFilter();
this.userDrawer = false;
},
},
};
</script>
<style lang="scss">
.user-drawer {
.el-drawer__header {
padding: 16px 24px;
margin: 0;
font-family: PingFang SC;
font-size: 16px;
font-weight: 500;
line-height: 24px;
color: #1f2329;
position: relative;
box-sizing: border-box;
height: 57px;
mix-blend-mode: normal;
border-bottom: 1px solid rgba(187, 191, 196, 0.5);
.el-drawer__close-btn {
position: absolute;
right: 24px;
top: 16px;
padding: 4px;
border-radius: 4px;
display: flex;
align-items: center;
justify-content: center;
}
.el-drawer__close-btn:hover {
background: #e9e9ea;
}
}
.el-drawer__body {
padding: 12px 24px 24px 24px;
position: relative;
}
.filter {
display: flex;
min-height: 46px;
> :nth-child(1) {
color: #1f2329;
font-family: "PingFang SC";
font-style: normal;
font-weight: 400;
font-size: 14px;
line-height: 24px;
white-space: nowrap;
width: 116px;
}
.filter-item {
flex: 1;
.item,
.more {
font-family: PingFang SC;
white-space: nowrap;
font-size: 14px;
font-weight: 400;
line-height: 24px;
margin-right: 12px;
text-align: center;
padding: 1px 6px;
background: #f5f6f7;
border-radius: 2px;
cursor: pointer;
display: inline-block;
margin-bottom: 12px;
}
.active,
.more:hover {
background: rgba(51, 112, 255, 0.1);
color: #0c296e;
}
.more {
white-space: nowrap;
}
}
}
.btn {
border-radius: 4px;
padding: 5px 26px 5px 26px;
font-family: PingFang SC;
font-size: 14px;
font-weight: 400;
line-height: 20px;
letter-spacing: 0px;
text-align: center;
border: none;
box-sizing: border-box;
}
.normal {
color: #1f2329;
border: 1px solid #bbbfc4;
margin-left: 12px;
}
.foot {
position: absolute;
right: 24px;
bottom: 24px;
text-align: right;
}
}
.user-popper {
padding: 0;
background: #fff;
.popper__arrow {
display: none;
}
}
.tree-select {
.el-select-dropdown__empty,
.el-scrollbar__wrap,
.popper__arrow {
display: none !important;
}
}
.user-popper.dept {
height: 400px;
overflow: auto;
}
</style>

View File

@@ -0,0 +1,459 @@
<template>
<el-drawer
:title="$t('user.filter_method')"
:visible.sync="userDrawer"
custom-class="user-drawer"
size="680px"
v-closePress
direction="rtl"
>
<div class="filter">
<span>{{ $t("dataset.datalist") }}</span>
<div class="filter-item">
<span
class="item"
@click="activeDatasetChange(ele.id)"
:class="[activeDataset.includes(ele.id) ? 'active' : '']"
:key="ele.id"
v-for="ele in selectDatasetsCahe"
>{{ ele.name }}</span
>
<el-popover
placement="bottom"
popper-class="user-popper"
width="200"
trigger="click"
>
<el-popover
placement="bottom"
popper-class="user-popper dept"
width="200"
trigger="click"
v-loading="treeLoading"
>
<el-tree
ref="datasetTreeRef"
current-node-key="id"
:data="treeData"
node-key="id"
highlight-current
:filter-node-method="filterNode"
:expand-on-click-node="true"
@node-click="nodeClick"
>
<span slot-scope="{ data }" class="custom-tree-node">
<span v-if="data.modelInnerType === 'group'">
<svg-icon icon-class="scene" class="ds-icon-scene" />
<span
style="
margin-left: 6px;
white-space: nowrap;
overflow: hidden;
text-overflow: ellipsis;
"
:title="data.name"
>{{ data.name }}</span
>
</span>
<span v-else>
<span>
<svg-icon
:icon-class="`ds-${data.modelInnerType}`"
:class="`ds-icon-${data.modelInnerType}`"
/>
</span>
<span
style="
margin-left: 6px;
white-space: nowrap;
overflow: hidden;
text-overflow: ellipsis;
"
:title="data.name"
>{{ data.name }}</span
>
</span>
</span>
</el-tree>
<el-select
ref="datasetSelect"
v-model="selectDatasets"
slot="reference"
popper-class="tree-select"
multiple
:placeholder="$t('commons.please_select')"
value-key="id"
>
<el-option
v-for="item in selectDatasets"
:key="item.name"
:label="item.name"
:value="item"
/>
</el-select>
</el-popover>
<span class="more" slot="reference">+ {{ $t("panel.more") }}</span>
</el-popover>
</div>
</div>
<div v-for="ele in filterDataset" :key="ele.name" class="filter">
<span>{{ $t(ele.name) }}</span>
<div class="filter-item">
<span
class="item"
@click="statusChange(item.value, ele.activeType)"
:class="[active[ele.activeType].includes(item.value) ? 'active' : '']"
:key="item.name"
v-for="item in ele.list"
>{{ $t(item.name) }}</span
>
</div>
</div>
<div class="filter">
<span>{{ $t("dedaterange.label") }}</span>
<div class="filter-item">
<el-date-picker
v-model="dataRange"
size="small"
type="daterange"
range-separator=""
start-placeholder="开始日期"
end-placeholder="结束日期"
>
</el-date-picker>
</div>
</div>
<div class="foot">
<el-button class="btn normal" @click="reset">{{
$t("commons.reset")
}}</el-button>
<el-button type="primary" class="btn" @click="search">{{
$t("commons.adv_search.search")
}}</el-button>
</div>
</el-drawer>
</template>
<script>
import { filterDatasetRecord, dateFormat } from "./options";
import { queryAuthModel } from "@/api/authModel/authModel";
export default {
data() {
return {
treeLoading: false,
filterTextMap: [],
dataRange: [],
selectDatasets: [],
datasetCahe: [],
activeDataset: [],
selectDatasetsCahe: [],
treeData: [],
filterDataset: [filterDatasetRecord],
active: {
execStatus: [],
},
userDrawer: false,
};
},
mounted() {
this.treeNode();
},
methods: {
treeNode() {
this.treeLoading = true;
queryAuthModel(
{
modelType: "dataset",
privileges: "manage",
datasetMode: 1,
clearEmptyDir: true,
mode: 1,
modelInnerTypeArray: ["db", "sql", "api", "group"],
},
true
)
.then((res) => {
this.treeData = res.data;
})
.finally(() => {
this.treeLoading = false;
});
},
nodeClick(data) {
const { id, name, modelInnerType: type } = data;
if (type === "group") return;
this.handleNodeClick(id, name);
},
filterNode(value, data) {
if (!value) return true;
return !this.activeDataset.includes(data.id);
},
clearFilter() {
this.active = {
execStatus: [],
}
this.dataRange = [];
this.activeDataset = [];
this.selectDatasets = [];
this.datasetCahe = [];
this.selectDatasetsCahe = [];
this.$emit("search", [], []);
},
clearOneFilter(index) {
(this.filterTextMap[index] || []).forEach(ele => {
const eleKey = ele.split('.');
if (eleKey.length === 2) {
const [p, c ] = eleKey;
this[p][c] = []
} else {
this[ele] = []
}
})
},
statusChange(value, type) {
const statusIndex = this.active[type].findIndex((ele) => ele === value);
if (statusIndex === -1) {
this.active[type].push(value);
} else {
this.active[type].splice(statusIndex, 1);
}
},
handleNodeClick(id, name) {
const datasetIdx = this.selectDatasets.findIndex((ele) => ele.id === id);
if (datasetIdx !== -1) {
this.selectDatasets.splice(datasetIdx, 1);
this.selectDatasetsCahe = this.selectDatasetsCahe.filter(
(ele) => ele.id !== id
);
this.datasetCahe = this.datasetCahe.filter((ele) => ele.id !== id);
this.$refs.datasetTreeRef.filter(id);
return;
}
this.activeDataset.push(id);
this.selectDatasetsCahe.push({ id, name });
this.datasetCahe.push({ id, name });
this.$refs.datasetTreeRef.filter(id);
},
activeDatasetChange(id) {
const dataset = this.datasetCahe.find((ele) => ele.id === id);
this.selectDatasets.push(dataset);
this.activeDataset = this.activeDataset.filter((ele) => ele !== id);
this.selectDatasetsCahe = this.selectDatasetsCahe.filter(
(ele) => ele.id !== id
);
},
search() {
this.userDrawer = false;
this.$emit("search", this.formatCondition(), this.formatText());
},
formatText() {
this.filterTextMap = [];
const params = [];
if (this.activeDataset.length) {
let str = `${this.$t("dataset.datalist")}:${this.activeDataset.reduce(
(pre, next) =>
(this.datasetCahe.find((ele) => ele.id === next) || {}).name +
"、" +
pre,
""
)}`;
params.push(str.slice(0, str.length - 1));
this.filterTextMap.push([
"activeDataset",
"selectDatasets",
"selectDatasetsCahe",
"datasetCahe",
]);
}
[
"dataset.task.last_exec_status",
].forEach((ele, index) => {
const { activeType: type, list } =
this.filterDataset[index];
console.log('type', type);
if (this.active[type].length) {
params.push(
`${this.$t(ele)}:${this.active[type]
.map((item) => this.$t(list.find((itx) => itx.value === item).name))
.join("、")}`
);
this.filterTextMap.push([`active.${type}`]);
}
});
if (this.dataRange.length) {
params.push(
`${this.$t("dedaterange.label")}:${this.dataRange
.map((ele) => {
return dateFormat("YYYY-mm-dd", ele);
})
.join("-")}`
);
this.filterTextMap.push(["dataRange"]);
}
return params;
},
formatCondition() {
const fildMap = {
"dataset_table_task.last_exec_status": this.active.execStatus,
"dataset_table.id": this.activeDataset,
};
const conditions = [];
Object.keys(fildMap).forEach((ele) => {
if (fildMap[ele].length) {
conditions.push({
field: ele,
operator: "in",
value: fildMap[ele],
});
}
});
const [ min, max ] = this.dataRange;
if (min && max) {
console.log(1, +min, +max);
conditions.push({
field: 'dataset_table_task.last_exec_time',
operator: "between",
value: [ +min, +max ],
})
}
return conditions;
},
init() {
this.userDrawer = true;
},
reset() {
this.clearFilter();
this.userDrawer = false;
},
},
};
</script>
<style lang="scss">
.user-drawer {
.el-drawer__header {
padding: 16px 24px;
margin: 0;
font-family: PingFang SC;
font-size: 16px;
font-weight: 500;
line-height: 24px;
color: #1f2329;
position: relative;
box-sizing: border-box;
height: 57px;
mix-blend-mode: normal;
border-bottom: 1px solid rgba(187, 191, 196, 0.5);
.el-drawer__close-btn {
position: absolute;
right: 24px;
top: 16px;
padding: 4px;
border-radius: 4px;
display: flex;
align-items: center;
justify-content: center;
}
.el-drawer__close-btn:hover {
background: #e9e9ea;
}
}
.el-drawer__body {
padding: 12px 24px 24px 24px;
position: relative;
}
.filter {
display: flex;
min-height: 46px;
> :nth-child(1) {
color: #1f2329;
font-family: "PingFang SC";
font-style: normal;
font-weight: 400;
font-size: 14px;
line-height: 24px;
white-space: nowrap;
width: 116px;
}
.filter-item {
flex: 1;
.item,
.more {
font-family: PingFang SC;
white-space: nowrap;
font-size: 14px;
font-weight: 400;
line-height: 24px;
margin-right: 12px;
text-align: center;
padding: 1px 6px;
background: #f5f6f7;
border-radius: 2px;
cursor: pointer;
display: inline-block;
margin-bottom: 12px;
}
.active,
.more:hover {
background: rgba(51, 112, 255, 0.1);
color: #0c296e;
}
.more {
white-space: nowrap;
}
}
}
.btn {
border-radius: 4px;
padding: 5px 26px 5px 26px;
font-family: PingFang SC;
font-size: 14px;
font-weight: 400;
line-height: 20px;
letter-spacing: 0px;
text-align: center;
border: none;
box-sizing: border-box;
}
.normal {
color: #1f2329;
border: 1px solid #bbbfc4;
margin-left: 12px;
}
.foot {
position: absolute;
right: 24px;
bottom: 24px;
text-align: right;
}
}
.user-popper {
padding: 0;
background: #fff;
.popper__arrow {
display: none;
}
}
.tree-select {
.el-select-dropdown__empty,
.el-scrollbar__wrap,
.popper__arrow {
display: none !important;
}
}
.user-popper.dept {
height: 400px;
overflow: auto;
}
</style>

View File

@@ -1,14 +1,615 @@
<template>
<div>数据同步表单</div>
<de-layout-content>
<div class="dataset-editer-form">
<div class="w600">
<el-form
ref="taskForm"
:form="taskForm"
:model="taskForm"
:disabled="disableForm"
label-width="100px"
class="de-form-item"
:rules="taskFormRules"
>
<el-form-item
@click.native="selectDataset"
:label="$t('chart.select_dataset')"
prop="datasetName"
>
<el-input
v-model="taskForm.datasetName"
size="small"
readonly
:placeholder="$t('dataset.task_name')"
/>
</el-form-item>
<el-form-item :label="$t('dataset.task_name')" prop="name">
<el-input
v-model="taskForm.name"
size="small"
:placeholder="$t('dataset.task_name')"
/>
</el-form-item>
<el-form-item :label="$t('dataset.update_type')" prop="type">
<el-radio-group v-model="taskForm.type">
<el-radio label="all_scope">{{
$t("dataset.all_scope")
}}</el-radio>
<el-radio label="add_scope">
{{ $t("dataset.add_scope") }}</el-radio
>
</el-radio-group>
</el-form-item>
<div class="add-scope-cont" v-if="taskForm.type === 'add_scope'">
<el-form-item :label="$t('dataset.incremental_update_type')">
<el-radio-group
v-model="incrementalUpdateType"
size="small"
@change="incrementalUpdateTypeChange"
>
<el-radio label="incrementalAdd">{{
$t("dataset.incremental_add")
}}</el-radio>
<el-radio label="incrementalDelete">{{
$t("dataset.incremental_delete")
}}</el-radio>
</el-radio-group>
<div class="param-title">
<span>{{ $t("dataset.param") }}</span>
<div class="param-title-btn">
<el-button
type="text"
size="small"
@click="insertParamToCodeMirror('${__last_update_time__}')"
>{{ $t("dataset.last_update_time") }}</el-button
>
<el-button
type="text"
size="small"
@click="
insertParamToCodeMirror('${__current_update_time__}')
"
>{{ $t("dataset.current_update_time") }}</el-button
>
</div>
</div>
<div class="codemirror-cont">
<codemirror
ref="myCm"
v-model="sql"
class="codemirror"
:options="sqlOption"
@ready="onCmReady"
@focus="onCmFocus"
@input="onCmCodeChange"
/>
</div>
</el-form-item>
</div>
<el-form-item :label="$t('dataset.execute_rate')" prop="rate">
<el-radio-group v-model="taskForm.rate" @change="onRateChange">
<el-radio label="SIMPLE">{{
$t("dataset.execute_once")
}}</el-radio>
<el-radio label="CRON">{{ $t("dataset.cron_config") }}</el-radio>
<el-radio label="SIMPLE_CRON">{{
$t("dataset.simple_cron")
}}</el-radio>
</el-radio-group>
</el-form-item>
<div class="execute-rate-cont" v-if="taskForm.rate !== 'SIMPLE'">
<el-form-item
v-if="taskForm.rate === 'SIMPLE_CRON'"
:label="$t('dataset.execute_rate')"
prop="rate"
>
<div class="simple-cron">
{{ $t("cron.every") }}
<el-input-number
v-model="taskForm.extraData.simple_cron_value"
controls-position="right"
:min="1"
size="small"
></el-input-number>
<el-select
v-model="taskForm.extraData.simple_cron_type"
filterable
size="small"
@change="onSimpleCronChange()"
>
<el-option
:label="$t('分钟')"
value="minute"
/>
<el-option :label="$t('小时')" value="hour" />
<el-option :label="$t('天')" value="day" />
</el-select>
{{ $t("cron.every_exec") }}
</div>
</el-form-item>
<el-form-item
prop="cron"
v-if="taskForm.rate === 'CRON'"
:label="$t('emailtask.cron_exp')"
>
<el-popover v-model="cronEdit">
<cron v-model="taskForm.cron" @close="cronEdit = false" />
<el-input
slot="reference"
v-model="taskForm.cron"
size="small"
style="width: 50%"
@click="cronEdit = true"
/>
</el-popover>
</el-form-item>
<el-form-item
v-if="taskForm.rate !== 'SIMPLE'"
:label="$t('dataset.start_time')"
prop="startTime"
>
<el-date-picker
v-model="taskForm.startTime"
type="datetime"
:placeholder="$t('dataset.start_time')"
size="small"
/>
</el-form-item>
<el-form-item
v-if="taskForm.rate !== 'SIMPLE'"
:label="$t('dataset.end_time')"
prop="end"
>
<el-radio-group v-model="taskForm.end">
<el-radio label="0">{{ $t("dataset.no_limit") }}</el-radio>
<el-radio label="1"> {{ $t("dataset.set_end_time") }}</el-radio>
</el-radio-group>
<el-date-picker
v-if="taskForm.end === '1'"
v-model="taskForm.endTime"
type="datetime"
:placeholder="$t('dataset.end_time')"
size="small"
/>
</el-form-item>
</div>
</el-form>
<table-selector
ref="tableSelector"
previewForTask="true"
privileges="manage"
@getTableId="getTableId"
:mode="1"
:clear-empty-dir="true"
:custom-type="['db', 'sql', 'api']"
show-mode="datasetTask"
/>
</div>
<div class="de-foot-layout">
<div class="cont">
<deBtn secondary @click="closeTask">{{ $t("dataset.cancel") }}</deBtn>
<deBtn v-if="!disableForm" type="primary" @click="saveTask(taskForm)">{{
$t("dataset.confirm")
}}</deBtn>
</div>
</div>
</div>
</de-layout-content>
</template>
<script>
import { post } from "@/api/dataset/dataset";
import DeLayoutContent from "@/components/business/DeLayoutContent";
import { hasDataPermission } from "@/utils/permission";
import msgCfm from "@/components/msgCfm/index";
import cron from "@/components/cron/cron";
import { codemirror } from "vue-codemirror";
import "codemirror/lib/codemirror.css";
import "codemirror/theme/eclipse.css";
import "codemirror/mode/sql/sql.js";
import "codemirror/addon/selection/active-line.js";
import "codemirror/addon/edit/closebrackets.js";
import "codemirror/mode/clike/clike.js";
import "codemirror/addon/edit/matchbrackets.js";
import "codemirror/addon/comment/comment.js";
import "codemirror/addon/dialog/dialog.js";
import "codemirror/addon/dialog/dialog.css";
import "codemirror/addon/search/searchcursor.js";
import "codemirror/addon/search/search.js";
import "codemirror/keymap/emacs.js";
import "codemirror/addon/hint/show-hint.css";
import "codemirror/addon/hint/sql-hint";
import "codemirror/addon/hint/show-hint";
import TableSelector from "./TableSelector";
export default {
name: 'AppearanceSetting',
components: { cron, codemirror, TableSelector, DeLayoutContent },
mixins: [msgCfm],
data() {
return {
disableForm: false,
table: {
name: "",
id: "",
},
taskForm: {
name: "",
type: "all_scope",
startTime: "",
tableId: "",
rate: "SIMPLE",
cron: "",
endTime: "",
end: "0",
extraData: {
simple_cron_type: "hour",
simple_cron_value: 1,
},
},
taskFormRules: {
name: [
{
required: true,
message: this.$t("dataset.required"),
trigger: "change",
},
{
min: 2,
max: 50,
message: this.$t("datasource.input_limit_2_50", [2, 50]),
trigger: "blur",
},
],
type: [
{
required: true,
message: this.$t("dataset.required"),
trigger: "change",
},
],
startTime: [
{
required: true,
message: this.$t("dataset.required"),
trigger: "change",
},
],
rate: [
{
required: true,
message: this.$t("dataset.required"),
trigger: "change",
},
],
end: [
{
required: true,
message: this.$t("dataset.required"),
trigger: "change",
},
],
cron: [
{
required: true,
message: this.$t("dataset.required"),
trigger: "change",
},
],
datasetName: [
{
required: true,
trigger: "change",
},
],
},
cronEdit: false,
sqlOption: {
tabSize: 2,
styleActiveLine: true,
lineNumbers: true,
line: true,
mode: "text/x-sql",
theme: "eclipse",
hintOptions: {
// 自定义提示选项
completeSingle: false, // 当匹配只有一项的时候是否自动补全
},
},
incrementalConfig: {},
sql: "",
incrementalUpdateType: "incrementalAdd",
};
},
created() {
const { datasetName, id } = this.$route.query;
this.taskDetail = { datasetName, id };
if (!id) return;
this.getTaskDetail(id);
},
methods: {
getTaskDetail(id) {
post(`/dataset/task/detail/${id}`, {}).then((res) => {
if(res.data.extraData) {
res.data.extraData = JSON.parse(res.data.extraData)
}
this.taskForm = res.data;
this.disableForm = this.disableEdit();
});
},
selectDataset() {
if (this.taskForm.id) return;
this.$refs.tableSelector.init();
},
getTableId(id, name) {
this.taskForm.tableId = id;
this.taskForm.datasetName = name;
},
onRateChange() {
if (this.taskForm.rate === "SIMPLE") {
this.taskForm.end = "0";
this.taskForm.endTime = "";
this.taskForm.cron = "";
}
if (this.taskForm.rate === "SIMPLE_CRON") {
this.taskForm.cron = "0 0 0/1 * * ? *";
}
if (this.taskForm.rate === "CRON") {
this.taskForm.cron = "00 00 * ? * * *";
}
},
disableEdit() {
const { privileges, rate, status } = this.taskForm;
return (
rate === "SIMPLE" ||
status === "Stopped" ||
!hasDataPermission("manage", privileges)
);
},
onCmReady(cm) {
// this.codemirror.setSize("-webkit-fill-available", "auto");
},
onCmFocus(cm) {},
onCmCodeChange(newCode) {
this.sql = newCode;
this.$emit("codeChange", this.sql);
},
closeTask() {
this.$router.back();
},
onSimpleCronChange() {
if (this.taskForm.extraData.simple_cron_type === "minute") {
if (
this.taskForm.extraData.simple_cron_value < 1 ||
this.taskForm.extraData.simple_cron_value > 59
) {
this.$message({
message: this.$t("cron.minute_limit"),
type: "warning",
showClose: true,
});
this.taskForm.extraData.simple_cron_value = 59;
}
this.taskForm.cron =
"0 0/" + this.taskForm.extraData.simple_cron_value + " * * * ? *";
return;
}
if (this.taskForm.extraData.simple_cron_type === "hour") {
if (
this.taskForm.extraData.simple_cron_value < 1 ||
this.taskForm.extraData.simple_cron_value > 23
) {
this.$message({
message: this.$t("cron.hour_limit"),
type: "warning",
showClose: true,
});
this.taskForm.extraData.simple_cron_value = 23;
}
this.taskForm.cron =
"0 0 0/" + this.taskForm.extraData.simple_cron_value + " * * ? *";
return;
}
if (this.taskForm.extraData.simple_cron_type === "day") {
if (
this.taskForm.extraData.simple_cron_value < 1 ||
this.taskForm.extraData.simple_cron_value > 31
) {
this.$message({
message: this.$t("cron.day_limit"),
type: "warning",
showClose: true,
});
this.taskForm.extraData.simple_cron_value = 31;
}
this.taskForm.cron =
"0 0 0 1/" + this.taskForm.extraData.simple_cron_value + " * ? *";
return;
}
},
insertParamToCodeMirror(param) {
const pos1 = this.$refs.myCm.codemirror.getCursor();
const pos2 = {};
pos2.line = pos1.line;
pos2.ch = pos1.ch;
this.$refs.myCm.codemirror.replaceRange(param, pos2);
},
saveTask(task) {
this.$refs.taskForm.validate((valid) => {
if (valid) {
if (task.rate !== "SIMPLE") {
if (this.incrementalUpdateType === "incrementalAdd") {
this.incrementalConfig.incrementalAdd = this.sql;
} else {
this.incrementalConfig.incrementalDelete = this.sql;
}
this.incrementalConfig.tableId = task.tableId;
}
task.startTime = new Date(task.startTime).getTime();
task.endTime = new Date(task.endTime).getTime();
const form = JSON.parse(JSON.stringify(task));
form.extraData = JSON.stringify(form.extraData);
const dataSetTaskRequest = {
datasetTableTask: form,
datasetTableIncrementalConfig:
task.type === "add_scope" ? this.incrementalConfig : undefined,
};
post("/dataset/task/save", dataSetTaskRequest).then((response) => {
this.openMessageSuccess("dataset.save_success");
this.closeTask();
});
} else {
return false;
}
});
},
getIncrementalConfig(tableId) {
post("/dataset/table/incrementalConfig", { tableId: tableId }).then(
(response) => {
this.incrementalConfig = response.data;
if (
this.incrementalConfig.incrementalAdd.length === 0 &&
this.incrementalConfig.incrementalDelete.length === 0
) {
this.incrementalUpdateType = "incrementalAdd";
this.sql = "";
return;
}
if (this.incrementalConfig.incrementalAdd.length > 0) {
this.incrementalUpdateType = "incrementalAdd";
this.sql = this.incrementalConfig.incrementalAdd;
} else {
this.incrementalUpdateType = "incrementalDelete";
this.sql = this.incrementalConfig.incrementalDelete;
}
}
);
},
incrementalUpdateTypeChange: function () {
if (this.incrementalUpdateType === "incrementalAdd") {
if (this.sql) {
this.incrementalConfig.incrementalDelete = this.sql;
} else {
this.incrementalConfig.incrementalDelete = "";
}
if (this.incrementalConfig.incrementalAdd) {
this.sql = this.incrementalConfig.incrementalAdd;
} else {
this.sql = "";
}
}
if (this.incrementalUpdateType === "incrementalDelete") {
if (this.sql) {
this.incrementalConfig.incrementalAdd = this.sql;
} else {
this.incrementalConfig.incrementalAdd = "";
}
if (this.incrementalConfig.incrementalDelete) {
this.sql = this.incrementalConfig.incrementalDelete;
} else {
this.sql = "";
}
}
},
},
};
</script>
<style lang="scss">
.dataset-editer-form {
display: flex;
align-items: center;
justify-content: center;
.w600 {
width: 600px;
padding-top: 24px;
padding-bottom: 24px;
.el-radio:not(:last-child) {
margin-right: 0;
width: 156px;
}
.simple-cron {
display: flex;
align-items: center;
width: 100%;
.el-input-number,
.el-select {
width: 140px;
margin-left: 8px;
}
.el-select {
margin-right: 8px;
}
}
.execute-rate-cont {
box-sizing: border-box;
padding: 20px;
width: 100%;
background: #f5f6f7;
border-radius: 4px;
.el-input__inner {
background: #ffffff !important;
}
.el-date-editor {
width: 100%;
}
}
.add-scope-cont {
height: 350px;
width: 100%;
border-radius: 4px;
padding: 20px;
.param-title {
width: 100%;
display: flex;
align-items: center;
justify-content: space-between;
padding-bottom: 9px;
&:nth-child(1) {
font-family: PingFang SC;
font-size: 14px;
font-weight: 400;
color: var(--deTextPrimary, #1f2329);
}
}
.codemirror-cont {
box-sizing: border-box;
width: 560px;
height: 200px;
background: #ffffff;
border: 1px solid #bbbfc4;
border-radius: 4px;
overflow: auto;
}
}
}
}
</script>
.de-foot-layout {
position: absolute;
width: calc(100% - 48px);
height: 80px;
bottom: 0;
right: 24px;
background: #ffffff;
box-shadow: 0px -2px 4px rgba(0, 0, 0, 0.08);
display: flex;
justify-content: center;
align-items: center;
z-index: 10;
.cont {
width: 600px;
text-align: right;
}
}
</style>

View File

@@ -0,0 +1,80 @@
const filterDatasetRecord = {
name: 'dataset.task.last_exec_status',
type: 'dataset_table_task.last_exec_status',
activeType: 'execStatus',
list: [{
name: 'xpacktask.success',
value: 'Completed',
}, {
name: 'dataset.task.exec',
value: 'Underway',
},
{
name: 'xpacktask.error',
value: 'Error',
}]
}
const filterDataset = [{
name: 'dataset.execute_rate',
type: 'dataset_table_task.rate',
activeType: 'rate',
list: [{
name: 'dataset.execute_once',
value: 'SIMPLE',
}, {
name: 'dataset.cron_config',
value: 'CRON',
},
{
name: 'dataset.simple_cron',
value: 'SIMPLE_CRON',
}]
}, {
name: 'dataset.task.task_status',
type: 'dataset_table_task.status',
activeType: 'status',
list: [{
name: 'dataset.task.underway',
value: 'Underway',
}, {
name: 'dataset.task.exec',
value: 'Exec',
},
{
name: 'dataset.task.pending',
value: 'Pending',
}, {
name: 'dataset.task.stopped',
value: 'Stopped',
}]
}, {
...filterDatasetRecord
}]
// 入参 fmt-格式 date-日期
function dateFormat(fmt, date) {
let ret;
const opt = {
"Y+": date.getFullYear().toString(), // 年
"m+": (date.getMonth() + 1).toString(), // 月
"d+": date.getDate().toString(), // 日
"H+": date.getHours().toString(), // 时
"M+": date.getMinutes().toString(), // 分
"S+": date.getSeconds().toString() // 秒
// 有其他格式化字符需求可以继续添加,必须转化成字符串
};
for (let k in opt) {
ret = new RegExp("(" + k + ")").exec(fmt);
if (ret) {
fmt = fmt.replace(ret[1], (ret[1].length == 1) ? (opt[k]) : (opt[k].padStart(ret[1].length, "0")))
};
};
return fmt;
}
export {
filterDataset,
dateFormat,
filterDatasetRecord
}

View File

@@ -861,72 +861,4 @@ export default {
}
}
</style>
<style lang="scss">
.de-confirm {
border: none;
.el-message-box__header {
display: none;
}
.el-message-box__content {
padding: 24px;
}
.el-message-box__container {
display: flex;
align-items: center;
}
.el-message-box__status {
height: 22px;
width: 22px;
font-size: 22px !important;
margin-right: 17px;
}
.el-message-box__message {
//styleName: 中文/桌面端/四级标题 16 24 Medium;
font-family: PingFang SC;
font-size: 16px;
font-weight: 500;
line-height: 24px;
letter-spacing: 0px;
text-align: left;
color: #1f2329;
}
.el-message-box__btns {
padding: 0;
}
.de-confirm-fail-btn {
height: 32px;
width: 80px;
border-radius: 4px;
font-family: PingFang SC;
font-size: 14px;
font-weight: 400;
line-height: 22px;
text-align: center;
padding: 0;
}
.de-confirm-fail-cancel {
background: #ffffff;
border: 1px solid #bbbfc4;
color: #1f2329;
}
.de-confirm-fail-confirm {
background: #f54a45;
border: none;
color: #ffffff;
}
}
.de-confirm-fail {
padding: 0 24px 24px 0 !important;
.el-message-box__status {
color: #ff8800 !important;
}
}
</style>