first commit
This commit is contained in:
@@ -0,0 +1,634 @@
|
||||
<!--#
|
||||
layout("/layouts/platform.html"){
|
||||
#-->
|
||||
<style>
|
||||
#app {
|
||||
display: flex;
|
||||
width: 100%;
|
||||
min-height: calc(100vh - 64px);
|
||||
justify-content: center;
|
||||
align-items: center;
|
||||
background-color: #f0f2f5;
|
||||
}
|
||||
|
||||
.box-card {
|
||||
width: calc(100% - 20px);
|
||||
min-height: calc(100vh - 84px);
|
||||
position: relative;
|
||||
}
|
||||
|
||||
.box-card .el-card__body {
|
||||
min-height: calc(100vh - 170px);
|
||||
position: relative;
|
||||
}
|
||||
|
||||
.box-card-title {
|
||||
font-size: 20px;
|
||||
}
|
||||
|
||||
.card-body {
|
||||
display: flex;
|
||||
justify-content: center;
|
||||
min-height: calc(100vh - 170px);
|
||||
position: relative;
|
||||
}
|
||||
|
||||
.card-body-center {
|
||||
width: 60%;
|
||||
min-width: 800px;
|
||||
min-height: calc(100vh - 170px);
|
||||
position: relative;
|
||||
padding-bottom: 70px;
|
||||
box-sizing: border-box;
|
||||
}
|
||||
|
||||
.card-body-center-bottom {
|
||||
position: absolute;
|
||||
left: 0;
|
||||
bottom: 0;
|
||||
width: 100%;
|
||||
display: flex;
|
||||
justify-content: center;
|
||||
}
|
||||
|
||||
.card-body-center-bottom button {
|
||||
margin: 0 10px;
|
||||
}
|
||||
|
||||
.card-body-center > .el-carousel {
|
||||
height: calc(100vh - 300px);
|
||||
min-height: 560px;
|
||||
position: relative;
|
||||
overflow-y: hidden;
|
||||
margin-top: 10px;
|
||||
}
|
||||
|
||||
.card-body-center > .el-carousel > .el-carousel__container {
|
||||
height: 100%;
|
||||
}
|
||||
|
||||
.carousel-table-item {
|
||||
display: flex;
|
||||
justify-content: center;
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
padding: 10px 0;
|
||||
box-sizing: border-box;
|
||||
}
|
||||
|
||||
.carousel-table-item-center {
|
||||
height: 100%;
|
||||
width: 90%;
|
||||
min-width: 800px;
|
||||
position: relative;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
overflow: hidden;
|
||||
}
|
||||
|
||||
.carousel-table-item-center .el-card__body {
|
||||
flex: 1;
|
||||
height: auto;
|
||||
min-height: 0;
|
||||
overflow-x: hidden;
|
||||
overflow-y: auto;
|
||||
box-sizing: border-box;
|
||||
padding-bottom: 20px;
|
||||
}
|
||||
|
||||
.check-group {
|
||||
display: block;
|
||||
overflow: visible;
|
||||
padding: 0 10px 5px 0;
|
||||
height: auto;
|
||||
min-height: 100%;
|
||||
box-sizing: border-box;
|
||||
}
|
||||
|
||||
.check-group .el-radio,
|
||||
.check-group .el-checkbox {
|
||||
display: block;
|
||||
width: 100%;
|
||||
box-sizing: border-box;
|
||||
padding: 12px;
|
||||
margin: 0 !important;
|
||||
margin-top: 15px !important;
|
||||
}
|
||||
|
||||
.check-group .el-checkbox__label,
|
||||
.check-group .el-radio__label {
|
||||
width: calc(100% - 16px);
|
||||
}
|
||||
|
||||
.option-extra {
|
||||
float: right;
|
||||
color: #f56c6c;
|
||||
}
|
||||
|
||||
.carousel-table-item-relation .el-card__body,
|
||||
.carousel-table-item-form .el-card__body {
|
||||
position: relative;
|
||||
height: 100%;
|
||||
box-sizing: border-box;
|
||||
}
|
||||
|
||||
.carousel-table-item-form .el-card__body {
|
||||
overflow-y: auto;
|
||||
}
|
||||
|
||||
.result-card {
|
||||
width: 100%;
|
||||
margin-top: 6px;
|
||||
}
|
||||
|
||||
.result-card .el-card__body {
|
||||
min-height: 170px;
|
||||
display: flex;
|
||||
justify-content: center;
|
||||
align-items: center;
|
||||
flex-direction: column;
|
||||
}
|
||||
|
||||
.result-text {
|
||||
font-size: 12px;
|
||||
color: rgb(100, 100, 100);
|
||||
margin-top: 20px;
|
||||
}
|
||||
</style>
|
||||
|
||||
<div id="app" v-cloak>
|
||||
<el-card class="box-card" shadow="never">
|
||||
<div slot="header" class="clearfix">
|
||||
<span class="box-card-title">DataKid</span>
|
||||
</div>
|
||||
|
||||
<div class="card-body">
|
||||
<div class="card-body-center">
|
||||
<el-steps :active="active" align-center>
|
||||
<el-step title="选择数据表" icon="el-icon-document-copy"></el-step>
|
||||
<el-step title="选择数据列" icon="el-icon-s-unfold"></el-step>
|
||||
<el-step title="数据列对应" icon="el-icon-s-operation"></el-step>
|
||||
<el-step title="提交数据" icon="el-icon-upload"></el-step>
|
||||
<el-step title="导入结果" icon="el-icon-bell"></el-step>
|
||||
</el-steps>
|
||||
|
||||
<el-carousel indicator-position="none" :autoplay="false" arrow="never" ref="carousel" direction="vertical">
|
||||
<el-carousel-item class="carousel-table-item">
|
||||
<el-card class="carousel-table-item-center">
|
||||
<div slot="header" class="clearfix">
|
||||
<el-input
|
||||
style="width: 200px"
|
||||
v-model.trim="tableKeyword"
|
||||
placeholder="请输入关键字查询"
|
||||
clearable>
|
||||
</el-input>
|
||||
<el-button type="primary" icon="el-icon-search" @click="filterTables"></el-button>
|
||||
<el-button v-if="formData.tableName" style="float: right; padding: 10px 0" type="text">
|
||||
当前选中:{{ formData.tableName }}
|
||||
</el-button>
|
||||
</div>
|
||||
|
||||
<el-radio-group class="check-group" v-model="formData.tableName">
|
||||
<el-radio
|
||||
v-for="item in filteredTables"
|
||||
:key="item.table_name"
|
||||
:label="item.table_name"
|
||||
border>
|
||||
{{ item.table_name }}{{ item.table_comment ? " ( " + item.table_comment + " )" : "" }}
|
||||
<span class="option-extra">rows: {{ item.table_rows || 0 }}</span>
|
||||
</el-radio>
|
||||
</el-radio-group>
|
||||
</el-card>
|
||||
</el-carousel-item>
|
||||
|
||||
<el-carousel-item class="carousel-table-item">
|
||||
<el-card class="carousel-table-item-center">
|
||||
<div slot="header" class="clearfix">
|
||||
<el-input
|
||||
style="width: 200px"
|
||||
v-model.trim="columnKeyword"
|
||||
placeholder="请输入关键字查询"
|
||||
clearable>
|
||||
</el-input>
|
||||
<el-button type="primary" icon="el-icon-search" @click="filterColumns"></el-button>
|
||||
<el-button style="float: right; padding: 10px 0" type="text">
|
||||
{{ formData.tableName }}
|
||||
</el-button>
|
||||
</div>
|
||||
|
||||
<el-checkbox-group class="check-group" v-model="formData.columns">
|
||||
<el-checkbox
|
||||
v-for="item in filteredColumns"
|
||||
:key="item.column_name"
|
||||
:label="item.column_name"
|
||||
border>
|
||||
{{ item.column_name }}{{ item.column_comment ? " ( " + item.column_comment + " )" : "" }}
|
||||
<span class="option-extra">{{ item.column_type }}</span>
|
||||
</el-checkbox>
|
||||
</el-checkbox-group>
|
||||
</el-card>
|
||||
</el-carousel-item>
|
||||
|
||||
<el-carousel-item class="carousel-table-item">
|
||||
<el-card style="width: 100%" class="carousel-table-item-relation">
|
||||
<el-table :data="relation" height="100%" style="width: 100%" border size="medium">
|
||||
<el-table-column prop="column_name" label="列名"></el-table-column>
|
||||
<el-table-column prop="column_comment" label="描述" show-overflow-tooltip></el-table-column>
|
||||
<el-table-column prop="is_nullable" label="可为空"></el-table-column>
|
||||
<el-table-column prop="column_type" label="类型"></el-table-column>
|
||||
<el-table-column prop="column_key" label="key"></el-table-column>
|
||||
<el-table-column min-width="200px">
|
||||
<template slot="header">
|
||||
目标列
|
||||
<el-popover
|
||||
placement="top-start"
|
||||
title="提示"
|
||||
trigger="hover"
|
||||
content="Excel 对应的表头名称,用于和表数据列对应">
|
||||
<i slot="reference" class="el-icon-question"></i>
|
||||
</el-popover>
|
||||
</template>
|
||||
<template slot-scope="{ row }">
|
||||
<el-input
|
||||
v-model.trim="row.relation"
|
||||
size="medium"
|
||||
placeholder="目标列">
|
||||
</el-input>
|
||||
</template>
|
||||
</el-table-column>
|
||||
</el-table>
|
||||
</el-card>
|
||||
</el-carousel-item>
|
||||
|
||||
<el-carousel-item class="carousel-table-item">
|
||||
<el-card style="width: 100%" class="carousel-table-item-form">
|
||||
<el-form label-width="120px" :model="formData" ref="form" :rules="formRules">
|
||||
<el-form-item label=" " label-width="135px" class="view-header"></el-form-item>
|
||||
|
||||
<el-form-item prop="method" label="导入方式">
|
||||
<el-radio-group v-model="formData.method">
|
||||
<el-radio-button :label="1">追加或更新</el-radio-button>
|
||||
<el-radio-button :label="2">仅追加</el-radio-button>
|
||||
<el-radio-button :label="3">仅更新</el-radio-button>
|
||||
</el-radio-group>
|
||||
</el-form-item>
|
||||
|
||||
<el-form-item v-if="[1, 3].includes(formData.method)" prop="field" label="关键字段">
|
||||
<el-select v-model="formData.field" clearable filterable placeholder="请选择" style="width: 50%">
|
||||
<el-option
|
||||
v-for="item in relation"
|
||||
:key="item.column_name"
|
||||
:label="item.column_name"
|
||||
:value="item.column_name">
|
||||
</el-option>
|
||||
</el-select>
|
||||
</el-form-item>
|
||||
|
||||
<el-form-item prop="plugins" label="可选插件">
|
||||
<el-checkbox-group v-model="formData.plugins">
|
||||
<el-checkbox
|
||||
v-for="item in plugins"
|
||||
:key="item.name"
|
||||
:label="item.name"
|
||||
border>
|
||||
{{ item.description }}
|
||||
</el-checkbox>
|
||||
</el-checkbox-group>
|
||||
</el-form-item>
|
||||
|
||||
<el-form-item label="文  件" class="is-required">
|
||||
<el-upload
|
||||
ref="upload"
|
||||
drag
|
||||
action="#"
|
||||
:auto-upload="false"
|
||||
:limit="1"
|
||||
:file-list="fileList"
|
||||
:on-change="handleFileChange"
|
||||
:on-remove="handleFileRemove">
|
||||
<i class="el-icon-upload"></i>
|
||||
<div class="el-upload__text">将文件拖到此处,或<em>点击上传</em></div>
|
||||
<div slot="tip" class="el-upload__tip" style="color: #F56C6C">只能上传 xls/xlsx 文件</div>
|
||||
</el-upload>
|
||||
</el-form-item>
|
||||
</el-form>
|
||||
</el-card>
|
||||
</el-carousel-item>
|
||||
|
||||
<el-carousel-item style="padding: 10px">
|
||||
<el-card class="result-card">
|
||||
<el-progress type="circle" :percentage="resultPercentage" :status="resultProgressStatus"></el-progress>
|
||||
<div class="result-text">{{ resultSummary }}</div>
|
||||
<div style="margin-top: 10px" v-if="result.cacheKey">
|
||||
<el-link
|
||||
type="danger"
|
||||
icon="el-icon-download"
|
||||
style="font-size: 13px;"
|
||||
:href="loc() + '/exportErrors?cacheKey=' + result.cacheKey">
|
||||
下载错误记录
|
||||
</el-link>
|
||||
</div>
|
||||
</el-card>
|
||||
</el-carousel-item>
|
||||
</el-carousel>
|
||||
|
||||
<div class="card-body-center-bottom">
|
||||
<el-button size="medium" @click="prev" :disabled="active === 0 || loading">上一步</el-button>
|
||||
<el-button type="primary" size="medium" :loading="loading" @click="active < 4 ? next() : carry()">
|
||||
{{ active < 4 ? primaryButtonText : "完成" }}
|
||||
</el-button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</el-card>
|
||||
</div>
|
||||
|
||||
<script nonce="${cspNonce!}">
|
||||
new Vue({
|
||||
el: "#app",
|
||||
data() {
|
||||
return {
|
||||
active: 0,
|
||||
loading: false,
|
||||
tableKeyword: "",
|
||||
columnKeyword: "",
|
||||
tables: [],
|
||||
filteredTables: [],
|
||||
columns: [],
|
||||
filteredColumns: [],
|
||||
relation: [],
|
||||
plugins: [],
|
||||
fileList: [],
|
||||
cacheTableName: "",
|
||||
result: {
|
||||
total: 0,
|
||||
success: 0,
|
||||
cacheKey: ""
|
||||
},
|
||||
formRules: {
|
||||
method: [{ required: true, message: "必填", trigger: ["blur", "change"] }],
|
||||
field: [{ required: true, message: "必填", trigger: ["blur", "change"] }]
|
||||
},
|
||||
formData: {
|
||||
tableName: "",
|
||||
columns: [],
|
||||
method: 1,
|
||||
field: "",
|
||||
plugins: []
|
||||
}
|
||||
}
|
||||
},
|
||||
computed: {
|
||||
primaryButtonText() {
|
||||
if (this.active === 3 && this.formData.method === 3) {
|
||||
return "更新"
|
||||
}
|
||||
return "下一步"
|
||||
},
|
||||
resultSummary() {
|
||||
const total = this.result.total || 0
|
||||
const success = this.result.success || 0
|
||||
const fail = Math.max(total - success, 0)
|
||||
if (fail > 0) {
|
||||
return "总记录数 " + total + " 条,成功 " + success + " 条,失败 " + fail + " 条!"
|
||||
}
|
||||
return "总记录数 " + total + " 条,成功 " + success + " 条!"
|
||||
},
|
||||
resultProgressStatus() {
|
||||
const total = this.result.total || 0
|
||||
const success = this.result.success || 0
|
||||
if (total > 0 && success < total) {
|
||||
return "exception"
|
||||
}
|
||||
return "success"
|
||||
},
|
||||
resultPercentage() {
|
||||
if (!this.result.total) {
|
||||
return 0
|
||||
}
|
||||
return Number(((this.result.success / this.result.total) * 100).toFixed(2))
|
||||
}
|
||||
},
|
||||
methods: {
|
||||
loc,
|
||||
normalizeRecord(item) {
|
||||
const normalized = {}
|
||||
Object.keys(item || {}).forEach(key => {
|
||||
normalized[(key || "").toLowerCase()] = item[key]
|
||||
})
|
||||
return normalized
|
||||
},
|
||||
async loadTables() {
|
||||
const resp = await this.$axios.post(loc() + "/tableNames")
|
||||
if (resp.code === 0) {
|
||||
this.tables = Array.isArray(resp.data)
|
||||
? resp.data.map(item => this.normalizeRecord(item))
|
||||
: []
|
||||
this.filteredTables = this.tables.slice()
|
||||
}
|
||||
},
|
||||
async loadPlugins() {
|
||||
this.plugins = await this.$businessTool.getEnumOptions("SysDataImportPlugin")
|
||||
},
|
||||
async loadColumns() {
|
||||
const resp = await this.$axios.post(loc() + "/columns", {
|
||||
tableName: this.formData.tableName
|
||||
})
|
||||
if (resp.code === 0) {
|
||||
this.columns = Array.isArray(resp.data)
|
||||
? resp.data.map(item => this.normalizeRecord(item))
|
||||
: []
|
||||
this.filteredColumns = this.columns.slice()
|
||||
}
|
||||
},
|
||||
filterTables() {
|
||||
const keyword = (this.tableKeyword || "").toLowerCase()
|
||||
if (!keyword) {
|
||||
this.filteredTables = this.tables.slice()
|
||||
return
|
||||
}
|
||||
this.filteredTables = this.tables.filter(item => {
|
||||
const tableName = (item.table_name || "").toLowerCase()
|
||||
const tableComment = (item.table_comment || "").toLowerCase()
|
||||
return tableName.includes(keyword) || tableComment.includes(keyword)
|
||||
})
|
||||
},
|
||||
filterColumns() {
|
||||
const keyword = (this.columnKeyword || "").toLowerCase()
|
||||
if (!keyword) {
|
||||
this.filteredColumns = this.columns.slice()
|
||||
return
|
||||
}
|
||||
this.filteredColumns = this.columns.filter(item => {
|
||||
const columnName = (item.column_name || "").toLowerCase()
|
||||
const columnComment = (item.column_comment || "").toLowerCase()
|
||||
return columnName.includes(keyword) || columnComment.includes(keyword)
|
||||
})
|
||||
},
|
||||
buildRelation() {
|
||||
this.relation = this.columns
|
||||
.filter(item => this.formData.columns.includes(item.column_name))
|
||||
.map(item => Object.assign({}, item, { relation: "" }))
|
||||
},
|
||||
async next() {
|
||||
if (this.active === 0) {
|
||||
if (!this.formData.tableName) {
|
||||
this.$notify({
|
||||
title: "警告",
|
||||
message: "请选择数据表",
|
||||
type: "warning"
|
||||
})
|
||||
return
|
||||
}
|
||||
if (this.cacheTableName !== this.formData.tableName) {
|
||||
await this.loadColumns()
|
||||
this.formData.columns = []
|
||||
this.formData.field = ""
|
||||
this.cacheTableName = this.formData.tableName
|
||||
}
|
||||
} else if (this.active === 1) {
|
||||
if (!this.formData.columns.length) {
|
||||
this.$notify({
|
||||
title: "警告",
|
||||
message: "请选择数据列",
|
||||
type: "warning"
|
||||
})
|
||||
return
|
||||
}
|
||||
this.buildRelation()
|
||||
} else if (this.active === 2) {
|
||||
if (this.relation.find(item => !item.relation)) {
|
||||
this.$notify({
|
||||
title: "警告",
|
||||
message: "存在未填写的目标列",
|
||||
type: "warning"
|
||||
})
|
||||
return
|
||||
}
|
||||
} else if (this.active === 3) {
|
||||
const success = await this.doSubmit()
|
||||
if (!success) {
|
||||
return
|
||||
}
|
||||
}
|
||||
|
||||
this.$refs.carousel.next()
|
||||
this.active++
|
||||
},
|
||||
prev() {
|
||||
if (this.active <= 0) {
|
||||
return
|
||||
}
|
||||
this.$refs.carousel.prev()
|
||||
this.active--
|
||||
},
|
||||
validateSubmitForm() {
|
||||
let validForm = true
|
||||
this.$refs.form.validate(valid => {
|
||||
validForm = valid
|
||||
})
|
||||
if (!validForm || !this.fileList.length) {
|
||||
this.$notify({
|
||||
title: "警告",
|
||||
message: "存在未填写的必填项",
|
||||
type: "warning"
|
||||
})
|
||||
return false
|
||||
}
|
||||
return true
|
||||
},
|
||||
async doSubmit() {
|
||||
if (!this.validateSubmitForm()) {
|
||||
return false
|
||||
}
|
||||
|
||||
const formData = new FormData()
|
||||
formData.append("tableName", this.formData.tableName)
|
||||
formData.append("method", this.formData.method)
|
||||
formData.append("field", this.formData.field || "")
|
||||
formData.append("relation", JSON.stringify(this.relation))
|
||||
formData.append("plugins", JSON.stringify(this.formData.plugins || []))
|
||||
formData.append("file", this.fileList[0].raw, this.fileList[0].name)
|
||||
|
||||
this.loading = true
|
||||
try {
|
||||
const resp = await this.$axios.post(loc() + "/importData", formData, {
|
||||
headers: {
|
||||
"Content-Type": "multipart/form-data"
|
||||
}
|
||||
})
|
||||
|
||||
if (resp.code !== 0) {
|
||||
this.$notify.error({
|
||||
title: "错误",
|
||||
message: resp.msg
|
||||
})
|
||||
this.result = { total: 0, success: 0, cacheKey: "" }
|
||||
return false
|
||||
}
|
||||
|
||||
this.result = resp.data || { total: 0, success: 0, cacheKey: "" }
|
||||
return true
|
||||
} finally {
|
||||
this.loading = false
|
||||
}
|
||||
},
|
||||
handleFileRemove(file, fileList) {
|
||||
this.fileList = fileList
|
||||
},
|
||||
handleFileChange(file, fileList) {
|
||||
const extension = ((file.name || "").split(".").pop() || "").toLowerCase()
|
||||
const remove = () => {
|
||||
const removeIndex = fileList.findIndex(item => item.uid === file.uid)
|
||||
if (removeIndex > -1) {
|
||||
fileList.splice(removeIndex, 1)
|
||||
}
|
||||
}
|
||||
|
||||
if (file.size === 0) {
|
||||
this.$message.warning("您选择的是空文件")
|
||||
remove()
|
||||
} else if (!["xls", "xlsx"].includes(extension)) {
|
||||
this.$message.warning("上传文件只能是 xls/xlsx 格式")
|
||||
remove()
|
||||
}
|
||||
|
||||
this.fileList = fileList
|
||||
},
|
||||
carry() {
|
||||
this.active = 0
|
||||
this.tableKeyword = ""
|
||||
this.columnKeyword = ""
|
||||
this.columns = []
|
||||
this.filteredColumns = []
|
||||
this.relation = []
|
||||
this.fileList = []
|
||||
this.cacheTableName = ""
|
||||
this.result = {
|
||||
total: 0,
|
||||
success: 0,
|
||||
cacheKey: ""
|
||||
}
|
||||
this.formData = {
|
||||
tableName: "",
|
||||
columns: [],
|
||||
method: 1,
|
||||
field: "",
|
||||
plugins: []
|
||||
}
|
||||
if (this.$refs.upload) {
|
||||
this.$refs.upload.clearFiles()
|
||||
}
|
||||
this.filterTables()
|
||||
this.$refs.carousel.setActiveItem(0)
|
||||
}
|
||||
},
|
||||
async created() {
|
||||
await this.loadTables()
|
||||
await this.loadPlugins()
|
||||
}
|
||||
})
|
||||
</script>
|
||||
<!--#
|
||||
}
|
||||
#-->
|
||||
@@ -0,0 +1,15 @@
|
||||
<!--#
|
||||
layout("/layouts/platform.html"){
|
||||
#-->
|
||||
|
||||
<div id="app" v-cloak></div>
|
||||
|
||||
<script nonce="${cspNonce!}">
|
||||
new Vue({
|
||||
el: "#app"
|
||||
})
|
||||
</script>
|
||||
|
||||
<!--#
|
||||
}
|
||||
#-->
|
||||
@@ -0,0 +1,211 @@
|
||||
<!--#
|
||||
layout("/layouts/platform.html"){
|
||||
#-->
|
||||
|
||||
<style>
|
||||
.pullTimeRadioGroup .el-checkbox {
|
||||
width: 100%;
|
||||
margin: 0 0 10px 0;
|
||||
}
|
||||
|
||||
.pullTimeRadioGroup .el-checkbox.is-bordered {
|
||||
margin-left: 0 !important;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
}
|
||||
|
||||
.pullTimeRadioGroup .el-checkbox__input {
|
||||
flex-shrink: 0;
|
||||
}
|
||||
|
||||
.pullTimeRadioGroup .el-checkbox__label {
|
||||
flex: 1;
|
||||
}
|
||||
</style>
|
||||
|
||||
<div id="app" v-cloak>
|
||||
<el-card shadow="never">
|
||||
<search @search="doSearch">
|
||||
<search-item label="拉取时间">
|
||||
<el-select clearable v-model="pageForm.pullTime" placeholder="请选择拉取时间" :clearable="false" @change="doSearch">
|
||||
<el-option v-for="item in pullTimeOptions" :label="item.pullTime" :value="item.pullTime"></el-option>
|
||||
</el-select>
|
||||
</search-item>
|
||||
<search-item label="姓名">
|
||||
<el-input placeholder="请输入姓名" clearable v-model="pageForm.userName" style="width: 100%"></el-input>
|
||||
</search-item>
|
||||
<search-item label="工号">
|
||||
<el-input placeholder="请输入工号" clearable v-model="pageForm.loginName" style="width: 100%"></el-input>
|
||||
</search-item>
|
||||
<search-item label="所属单位">
|
||||
<el-select placeholder="请选择所属单位" v-model="pageForm.unitName" clearable filterable>
|
||||
<el-option v-for="item in unitNameOptions" :key="item" :label="item" :value="item"></el-option>
|
||||
</el-select>
|
||||
</search-item>
|
||||
<search-item label="在职状态">
|
||||
<el-select v-model="pageForm.userState" clearable filterable>
|
||||
<el-option v-for="item in userStateOptions" :label="item" :value="item"></el-option>
|
||||
</el-select>
|
||||
</search-item>
|
||||
<search-item label="用人方式">
|
||||
<el-select v-model="pageForm.preparedBy" clearable filterable>
|
||||
<el-option v-for="item in preparedByOptions" :label="item" :value="item"></el-option>
|
||||
</el-select>
|
||||
</search-item>
|
||||
<search-item label="人员类型">
|
||||
<el-select v-model="pageForm.personType" clearable filterable>
|
||||
<el-option v-for="item in personTypeOptions" :label="item" :value="item"></el-option>
|
||||
</el-select>
|
||||
</search-item>
|
||||
</search>
|
||||
</el-card>
|
||||
|
||||
<el-card shadow="never">
|
||||
<table-tool :label="pageForm.pullTime ? pageForm.pullTime + '数据' : '全部数据'">
|
||||
<el-button type="primary" size="mini" :loading="pullLoading" @click="pull" icon="el-icon-download">拉取信息中心数据</el-button>
|
||||
<el-button type="danger" size="mini" @click="openDelete" icon="el-icon-delete">删除本地数据源</el-button>
|
||||
</table-tool>
|
||||
<el-table :key="tableKey" :data="tableData" @sort-change="pageOrder" header-align="center" v-loading="tableLoading">
|
||||
<el-table-column type="index" width="70" label="序号" fixed="left" :index="indexMethod"></el-table-column>
|
||||
<el-table-column prop="pullTime" label="拉取时间" width="170" fixed="left"></el-table-column>
|
||||
<el-table-column prop="loginname" label="工号" width="100" fixed="left"></el-table-column>
|
||||
<el-table-column prop="username" label="姓名" fixed="left" width="120" show-overflow-tooltip></el-table-column>
|
||||
<el-table-column prop="sex" label="性别" sortable></el-table-column>
|
||||
<el-table-column prop="mobile" label="手机号" width="120"></el-table-column>
|
||||
<el-table-column prop="birthday" label="生日" sortable width="120">
|
||||
<template slot-scope="{row}">{{$moment(row.birthday).format('YYYY-MM-DD')}}</template>
|
||||
</el-table-column>
|
||||
<el-table-column prop="userState" label="在职状态" sortable width="120"></el-table-column>
|
||||
<el-table-column prop="arrivalAtSchoolDate" label="来校时间" sortable width="120"></el-table-column>
|
||||
<el-table-column prop="personType" label="人员类型" sortable width="120"></el-table-column>
|
||||
<!-- <el-table-column prop="technicalTitle" label="技术职称" sortable width="120"></el-table-column>
|
||||
<el-table-column prop="position" label="干部职务" sortable width="120" show-overflow-tooltip></el-table-column>
|
||||
<el-table-column prop="education" label="学历" show-overflow-tooltip sortable width="120"></el-table-column>
|
||||
<el-table-column prop="academicDegree" label="学位" show-overflow-tooltip sortable width="120"></el-table-column>-->
|
||||
<el-table-column prop="unitName" label="单位" show-overflow-tooltip sortable width="120"></el-table-column>
|
||||
<el-table-column prop="unitId" label="单位编码" sortable width="120"></el-table-column>
|
||||
<el-table-column prop="political" label="政治面貌" sortable></el-table-column>
|
||||
<el-table-column prop="nation" label="民族" sortable></el-table-column>
|
||||
</el-table>
|
||||
<!--#include("/layouts/pagination.html"){}#-->
|
||||
</el-card>
|
||||
|
||||
<el-dialog title="选择数据源" :visible.sync="pullTimeDialogVisible" width="30%">
|
||||
<el-checkbox-group v-model="sourceTime" style="width: 100%" class="pullTimeRadioGroup">
|
||||
<el-checkbox :label="item.pullTime" border v-for="item in pullTimeOptions" :key="item.pullTime">
|
||||
<div style="display: flex; justify-content: space-between">
|
||||
{{item.pullTime}}
|
||||
<span style="color: red">rows:{{item.num}}</span>
|
||||
</div>
|
||||
</el-checkbox>
|
||||
</el-checkbox-group>
|
||||
<span slot="footer" class="dialog-footer">
|
||||
<el-button @click="pullTimeDialogVisible = false">取 消</el-button>
|
||||
<el-button type="primary" @click="doDeleteUser">确 定</el-button>
|
||||
</span>
|
||||
</el-dialog>
|
||||
</div>
|
||||
|
||||
<script nonce="${cspNonce!}">
|
||||
new Vue({
|
||||
el: "#app",
|
||||
mixins: [initTableMixins],
|
||||
data() {
|
||||
return {
|
||||
unitNameOptions: [],
|
||||
userStateOptions: [],
|
||||
preparedByOptions: [],
|
||||
personTypeOptions: [],
|
||||
pullTimeOptions: false,
|
||||
sourceTime: [],
|
||||
pullTimeDialogVisible: false,
|
||||
pullLoading: false
|
||||
}
|
||||
},
|
||||
methods: {
|
||||
pull() {
|
||||
this.$confirm("确定要拉取数据源吗?", "提示", {
|
||||
type: "warning",
|
||||
confirmButtonText: "确定",
|
||||
cancelButtonText: "取消"
|
||||
})
|
||||
.then(() => {
|
||||
this.pullLoading = true
|
||||
this.$axios
|
||||
.post("/platform/sys/data/user/pull/pullData")
|
||||
.then((resp) => {
|
||||
if (resp.code === 0) {
|
||||
this.$message.success(resp.msg)
|
||||
this.getPullTimeOptions()
|
||||
this.doSearch()
|
||||
}
|
||||
})
|
||||
.finally(() => {
|
||||
this.pullLoading = false
|
||||
})
|
||||
})
|
||||
.catch(() => {})
|
||||
},
|
||||
|
||||
getSearchOptions() {
|
||||
this.$axios.post("/platform/sys/data/user/pull/searchOptions").then((resp) => {
|
||||
if (resp.code === 0) {
|
||||
this.unitNameOptions = resp.data.unitNames
|
||||
this.userStateOptions = resp.data.userStates
|
||||
this.personTypeOptions = resp.data.personTypes
|
||||
this.preparedByOptions = resp.data.preparedBys
|
||||
}
|
||||
})
|
||||
},
|
||||
getPullTimeOptions() {
|
||||
this.$axios.post("/platform/sys/data/user/pull/pullTimeOptions").then((resp) => {
|
||||
if (resp.code === 0) {
|
||||
this.pullTimeOptions = resp.data
|
||||
if (this.pullTimeOptions.length > 0) {
|
||||
this.pageForm.pullTime = this.pullTimeOptions[0].pullTime
|
||||
this.pageData()
|
||||
} else {
|
||||
this.tableData = []
|
||||
this.pageForm.totalCount = 0
|
||||
}
|
||||
}
|
||||
})
|
||||
},
|
||||
|
||||
openDelete() {
|
||||
this.pullTimeDialogVisible = true
|
||||
this.getPullTimeOptions()
|
||||
},
|
||||
|
||||
doDeleteUser() {
|
||||
this.$confirm("确定要删除数据源吗?", "提示", {
|
||||
type: "warning",
|
||||
confirmButtonText: "确定",
|
||||
cancelButtonText: "取消"
|
||||
}).then(() => {
|
||||
this.$axios
|
||||
.post("/platform/sys/data/user/pull/deleteByPullTime", {
|
||||
pullTime: JSON.stringify(this.sourceTime)
|
||||
})
|
||||
.then((resp) => {
|
||||
if (resp.code === 0) {
|
||||
this.$message.success(resp.msg)
|
||||
this.pullTimeDialogVisible = false
|
||||
this.doSearch()
|
||||
}
|
||||
})
|
||||
})
|
||||
}
|
||||
},
|
||||
created() {
|
||||
// this.pageData()
|
||||
this.getSearchOptions()
|
||||
this.getPullTimeOptions()
|
||||
}
|
||||
})
|
||||
</script>
|
||||
|
||||
<!--#
|
||||
}
|
||||
#-->
|
||||
|
||||
@@ -0,0 +1,313 @@
|
||||
<!--#
|
||||
layout("/layouts/platform.html"){
|
||||
#-->
|
||||
|
||||
<style>
|
||||
.pullTimeRadioGroup .el-radio {
|
||||
width: 100%;
|
||||
margin-bottom: 10px;
|
||||
}
|
||||
|
||||
.pullTimeRadioGroup .el-radio.is-bordered + .el-radio.is-bordered {
|
||||
margin-left: 0;
|
||||
}
|
||||
|
||||
.condition-builder {
|
||||
border: 1px solid #dcdfe6;
|
||||
border-radius: 4px;
|
||||
padding: 10px;
|
||||
margin-bottom: 10px;
|
||||
}
|
||||
</style>
|
||||
|
||||
<div id="app" v-cloak>
|
||||
<guava ref="guava">
|
||||
<template>
|
||||
<el-card shadow="never">
|
||||
<search @search="doSearch">
|
||||
<search-item label="姓名">
|
||||
<el-input placeholder="请输入姓名" clearable v-model="pageForm.userName" style="width: 100%"></el-input>
|
||||
</search-item>
|
||||
<search-item label="工号">
|
||||
<el-input placeholder="请输入工号" clearable v-model="pageForm.loginName" style="width: 100%"></el-input>
|
||||
</search-item>
|
||||
<search-item label="所属单位">
|
||||
<el-select placeholder="请选择所属单位" v-model="pageForm.unitId" clearable style="width: 100%">
|
||||
<el-option v-for="i in unitOptions" :label="i.name" :key="i.id" :value="i.id"></el-option>
|
||||
</el-select>
|
||||
</search-item>
|
||||
<search-item label="在职状态">
|
||||
<dict-select v-model="pageForm.userState" code="USER_STATE" style="width: 100%"></dict-select>
|
||||
</search-item>
|
||||
<search-item label="人员类型">
|
||||
<dict-select v-model="pageForm.personType" code="USER_PERSON_TYPE" style="width: 100%"></dict-select>
|
||||
</search-item>
|
||||
</search>
|
||||
</el-card>
|
||||
|
||||
<el-card shadow="never">
|
||||
<table-tool label="系统当前用户数据">
|
||||
<!--<el-button type="primary" size="mini" @click="updateDataDict" icon="el-icon-refresh">更新【码表】数据</el-button>-->
|
||||
<el-button type="primary" size="mini" @click="updateUnits" icon="el-icon-refresh">更新【单位】数据</el-button>
|
||||
<el-button type="primary" size="mini" @click="openUpdate" icon="el-icon-refresh">更新【人员】数据</el-button>
|
||||
</table-tool>
|
||||
<el-table :key="tableKey" :data="tableData" @sort-change="pageOrder" header-align="center">
|
||||
<el-table-column type="index" width="70" label="序号" fixed="left"></el-table-column>
|
||||
<el-table-column prop="loginname" label="工号" width="100" fixed="left"></el-table-column>
|
||||
<el-table-column prop="username" label="姓名" fixed="left" width="120" show-overflow-tooltip></el-table-column>
|
||||
<el-table-column prop="changeTypes" label="变更类型" width="140">
|
||||
<template slot-scope="{row}">
|
||||
<span style="color: #0e78c5; cursor: pointer" @click="openCurrentUserChangeInfo(row)">
|
||||
{{getChangeTypes(row.changeTypes)}}
|
||||
</span>
|
||||
</template>
|
||||
</el-table-column>
|
||||
<el-table-column prop="changeTime" label="变更时间" sortable width="150"></el-table-column>
|
||||
<el-table-column prop="sex" label="性别" sortable></el-table-column>
|
||||
<!-- <el-table-column prop="mobile" label="手机号" width="120"></el-table-column>-->
|
||||
<el-table-column prop="birthday" label="生日" sortable width="120">
|
||||
<template slot-scope="{row}">{{$moment(row.birthday).format('YYYY-MM-DD')}}</template>
|
||||
</el-table-column>
|
||||
<el-table-column prop="userState" label="在职状态" sortable width="120"></el-table-column>
|
||||
<el-table-column prop="personType" label="人员类型" sortable width="120"></el-table-column>
|
||||
<el-table-column prop="arrivalAtSchoolDate" label="来校年月" sortable width="120"></el-table-column>
|
||||
<!--<el-table-column prop="technicalTitle" label="技术职称" sortable width="120"></el-table-column>
|
||||
<el-table-column prop="position" label="职务" sortable width="120" show-overflow-tooltip></el-table-column>
|
||||
<el-table-column prop="education" label="学历" show-overflow-tooltip sortable width="120"></el-table-column>
|
||||
<el-table-column prop="academicDegree" label="学位" show-overflow-tooltip sortable width="120"></el-table-column>-->
|
||||
<el-table-column prop="unitName" label="单位" show-overflow-tooltip sortable width="120"></el-table-column>
|
||||
<el-table-column prop="unitId" label="单位编码" sortable width="120"></el-table-column>
|
||||
<el-table-column prop="political" label="政治面貌" sortable></el-table-column>
|
||||
<el-table-column prop="nation" label="民族" sortable></el-table-column>
|
||||
</el-table>
|
||||
<!--#include("/layouts/pagination.html"){}#-->
|
||||
</el-card>
|
||||
</template>
|
||||
|
||||
<template #view>
|
||||
<member-all-change-info ref="memberAllChangeInfoRef"></member-all-change-info>
|
||||
</template>
|
||||
|
||||
</guava>
|
||||
<el-dialog title="选择数据源" :visible.sync="updateDialog" width="70%">
|
||||
<el-timeline>
|
||||
<el-timeline-item timestamp="数据源" placement="top">
|
||||
<el-radio-group v-model="updateFromData.pullTime" style="width: 100%" class="pullTimeRadioGroup">
|
||||
<el-radio :label="item.pullTime" border v-for="item in pullTimeOptions" :key="item.pullTime">
|
||||
<span>
|
||||
{{item.pullTime}}
|
||||
<span style="float: right; color: red">rows:{{item.num}}</span>
|
||||
</span>
|
||||
</el-radio>
|
||||
</el-radio-group>
|
||||
</el-timeline-item>
|
||||
|
||||
<el-timeline-item timestamp="更新方式" placement="top">
|
||||
<el-radio-group class="checkGroup" style="width: 100%" v-model="updateFromData.updateMode" size="small">
|
||||
<el-row>
|
||||
<el-radio border label="ALL">全部更新</el-radio>
|
||||
<el-radio border label="INCR">仅更新新增人员</el-radio>
|
||||
</el-row>
|
||||
</el-radio-group>
|
||||
</el-timeline-item>
|
||||
|
||||
<el-timeline-item timestamp="高级条件筛选" placement="top">
|
||||
<el-switch v-model="enableAdvancedConditions" active-text="启用高级条件"></el-switch>
|
||||
|
||||
<div v-if="enableAdvancedConditions" class="condition-builder">
|
||||
<!-- 条件构建器组件 -->
|
||||
<condition-group :group="updateFromData.conditionGroup" :field_options="fieldOptions" @remove="removeRootGroup"></condition-group>
|
||||
</div>
|
||||
</el-timeline-item>
|
||||
</el-timeline>
|
||||
<span slot="footer" class="dialog-footer">
|
||||
<el-button @click="updateDialog = false" :disabled="updateLoading">取 消</el-button>
|
||||
<el-button type="primary" @click="execUpdate" :disabled="updateLoading" :loading="updateLoading">确 定</el-button>
|
||||
</span>
|
||||
</el-dialog>
|
||||
</div>
|
||||
|
||||
<script nonce="${cspNonce!}">
|
||||
<!--#include("../../../zhgh/staffmanage/member/change/common/memberAllChangeInfo.js"){}#-->
|
||||
|
||||
new Vue({
|
||||
el: "#app",
|
||||
mixins: [initTableMixins],
|
||||
data() {
|
||||
return {
|
||||
updateDialog: false,
|
||||
pullTimeOptions: false,
|
||||
updateFromData: {
|
||||
pullTime: null,
|
||||
updateMode: "ALL",
|
||||
conditionGroup: {
|
||||
logic: "AND",
|
||||
conditions: [],
|
||||
groups: []
|
||||
}
|
||||
},
|
||||
updateLoading: false,
|
||||
unitOptions: [],
|
||||
changeTypeData: [],
|
||||
enableAdvancedConditions: false,
|
||||
// 可选字段列表
|
||||
fieldOptions: [
|
||||
{ label: "姓名", value: "username" },
|
||||
{ label: "工号", value: "loginname" },
|
||||
{ label: "性别", value: "sex" },
|
||||
{ label: "生日", value: "birthday" },
|
||||
{ label: "手机号", value: "mobile" },
|
||||
{ label: "在职状态", value: "userState" },
|
||||
{ label: "进站时间", value: "postDoctoralJoinDate" },
|
||||
{ label: "人员类型", value: "personType" },
|
||||
{ label: "来校年月", value: "arrivalAtSchoolDate" },
|
||||
{ label: "单位", value: "unitName" },
|
||||
{ label: "单位编码", value: "unitId" },
|
||||
{ label: "学历", value: "education" },
|
||||
{ label: "学位", value: "academicDegree" }
|
||||
]
|
||||
}
|
||||
},
|
||||
components: {
|
||||
"member-all-change-info": MEMBER_ALL_CHANGE_INFO
|
||||
},
|
||||
methods: {
|
||||
// 更新单位数据
|
||||
updateUnits() {
|
||||
this.$confirm("确定要更新单位数据吗?", "提示", {
|
||||
confirmButtonText: "确定",
|
||||
cancelButtonText: "取消",
|
||||
type: "warning"
|
||||
}).then(() => {
|
||||
this.$axios.post("/platform/sys/data/user/update/updateUnits")
|
||||
.then((resp) => {
|
||||
if (resp.code === 0) {
|
||||
this.$message.success("更新成功")
|
||||
} else {
|
||||
this.$message.error(resp.msg)
|
||||
}
|
||||
})
|
||||
})
|
||||
|
||||
},
|
||||
// 更新码表数据
|
||||
updateDataDict() {
|
||||
this.$confirm("确定要更新码表数据吗?", "提示", {
|
||||
confirmButtonText: "确定",
|
||||
cancelButtonText: "取消",
|
||||
type: "warning"
|
||||
}).then(() => {
|
||||
this.$axios.post("/platform/sys/data/user/update/updateDataDict")
|
||||
.then((resp) => {
|
||||
if (resp.code === 0) {
|
||||
this.$message.success("更新成功")
|
||||
} else {
|
||||
this.$message.error(resp.msg)
|
||||
}
|
||||
})
|
||||
})
|
||||
},
|
||||
openCurrentUserChangeInfo(row) {
|
||||
this.$refs.guava.view(() => {
|
||||
this.$refs.memberAllChangeInfoRef.onOpen(row.id)
|
||||
})
|
||||
},
|
||||
getChangeTypes(changeTypes) {
|
||||
if (!changeTypes) return null
|
||||
const changeTypesList = JSON.parse(changeTypes)
|
||||
if (changeTypesList) {
|
||||
if (!changeTypesList || changeTypesList.length === 0 || !this.changeTypeData || this.changeTypeData.length === 0) return null
|
||||
return changeTypesList
|
||||
.map((v) => {
|
||||
return this.changeTypeData.find((item) => item.code === v).changeTypeName
|
||||
})
|
||||
.join(",")
|
||||
}
|
||||
return null
|
||||
},
|
||||
openUpdate() {
|
||||
this.updateDialog = true
|
||||
this.updateLoading = false
|
||||
this.$nextTick(() => {
|
||||
this.updateFromData = {
|
||||
updateMode: "ALL",
|
||||
pullTime: null,
|
||||
conditionGroup: {
|
||||
logic: "AND",
|
||||
conditions: [],
|
||||
groups: []
|
||||
}
|
||||
}
|
||||
this.enableAdvancedConditions = false
|
||||
})
|
||||
},
|
||||
getPullTimeOptions() {
|
||||
this.$axios.post("/platform/sys/data/user/update/pullTimeOptions").then((resp) => {
|
||||
if (resp.code === 0) {
|
||||
this.pullTimeOptions = resp.data
|
||||
}
|
||||
})
|
||||
},
|
||||
execUpdate() {
|
||||
if (!this.updateFromData.pullTime) {
|
||||
this.$message.warning("请选择数据源时间")
|
||||
return
|
||||
}
|
||||
if (!this.updateFromData.updateMode) {
|
||||
this.$message.warning("请选择更新方式")
|
||||
return
|
||||
}
|
||||
|
||||
// 如果未启用高级条件,则移除条件组
|
||||
if (!this.enableAdvancedConditions) {
|
||||
this.updateFromData.conditionGroup = null
|
||||
}
|
||||
|
||||
this.$confirm("确定要更新数据吗?", "提示", {
|
||||
confirmButtonText: "确定",
|
||||
cancelButtonText: "取消",
|
||||
type: "warning"
|
||||
})
|
||||
.then(() => {
|
||||
this.updateLoading = true
|
||||
this.$axios
|
||||
.post("/platform/sys/data/user/update/updateUserFormSource", { param: JSON.stringify(this.updateFromData) })
|
||||
.then((resp) => {
|
||||
if (resp.code === 0) {
|
||||
this.$message.success(resp.msg)
|
||||
this.updateDialog = false
|
||||
this.pageData()
|
||||
}
|
||||
})
|
||||
.finally(() => {
|
||||
this.updateLoading = false
|
||||
})
|
||||
})
|
||||
},
|
||||
listUnit() {
|
||||
this.$businessTool.listUnit(this.pageForm.unionId).then((res) => {
|
||||
this.unitOptions = res
|
||||
})
|
||||
},
|
||||
removeRootGroup() {
|
||||
// 重置根条件组
|
||||
this.updateFromData.conditionGroup = {
|
||||
logic: "AND",
|
||||
conditions: [],
|
||||
groups: []
|
||||
}
|
||||
}
|
||||
},
|
||||
async created() {
|
||||
this.listUnit()
|
||||
this.getPullTimeOptions()
|
||||
this.pageData()
|
||||
this.changeTypeData = await this.$businessTool.getEnumOptions("MemberChangeType")
|
||||
}
|
||||
})
|
||||
</script>
|
||||
|
||||
<!--#
|
||||
}
|
||||
#-->
|
||||
|
||||
Reference in New Issue
Block a user