first commit

This commit is contained in:
2026-09-09 09:14:28 +08:00
commit 5343198112
5199 changed files with 1052895 additions and 0 deletions
@@ -0,0 +1,138 @@
<template>
<el-dialog
title="高级查询构造器"
:visible.sync="dialogVisible"
:close-on-click-modal="false"
width="50%">
<el-row type="flex">
<el-col style="display:flex;align-items: center;width: 200px">
<vi-title title="过滤条件匹配:" style="display:flex;align-items: center;margin-bottom: 0"></vi-title>
</el-col>
<el-col>
<enum-select v-model="value.method" value="name" :clearable="false" label="description" style="width: 300px"
enum="MatchMethod"></enum-select>
</el-col>
</el-row>
<el-row v-for="(cnd,idx) in value.conditions" gutter="20" style="margin-top: 20px" type="flex">
<el-col span="7">
<el-select v-model="cnd.field" placeholder="请选择字段" style="width: 100%" @change="(v)=>fieldChange(v,cnd)">
<el-option
v-for="item in fields"
:key="item.value"
:label="item.label"
:value="item.value">
</el-option>
</el-select>
</el-col>
<el-col span="4">
<enum-select v-model="cnd.operational" value="name" :clearable="false" label="description" style="width: 100%"
enum="ConditionalOperational"></enum-select>
</el-col>
<el-col span="9">
<el-select v-if="cnd.fieldObj&&cnd.fieldObj.type=='select'" v-model="cnd.value" placeholder="请选择值"
style="width: 100%"
clearable>
<el-option
v-for="item in cnd.fieldObj.options"
:key="item.value"
:label="item.label"
:value="item.value">
</el-option>
</el-select>
<el-date-picker
v-else-if="cnd.fieldObj&&cnd.fieldObj.type=='date'"
v-model="cnd.value"
type="date"
value-format="yyyy-MM-dd"
placeholder="请选择日期" style="width: 100%">
</el-date-picker>
<el-input v-else v-model="cnd.value" clearable placeholder="请输入值" style="width: 100%"></el-input>
</el-col>
<el-col style="width: 180px">
<el-button icon="el-icon-plus" @click="value.conditions.splice(idx+1, 0, {})"></el-button>
<el-button icon="el-icon-minus" :disabled="value.conditions.length==1"
@click="value.conditions.splice(idx, 1)"></el-button>
</el-col>
</el-row>
<span slot="footer" class="dialog-footer">
<el-button @click="dialogVisible = false"> </el-button>
<el-button type="primary" @click="doSubmit">{{ submit_text }}</el-button>
</span>
</el-dialog>
</template>
<script>
module.exports = {
props: {
value: {
type: Object, default: {
method: "AND",
conditions: [{}],
}
},
fields: [],
submit_text: {type: String, default: '确 定'}
},
model: {
prop: 'value',
event: 'confirm'
},
components: {'enum-select': httpVueLoader('/components/plugins/EnumSelect.vue?v=1.0.0'),},
data() {
return {
dialogVisible: false
}
},
watch: {
value: {
deep: true,
handler: function (value) {
if (value.conditions.length) {
value.conditions.map(v => {
const field = this.fields.find(x => x.value == v.field)
v.fieldObj = field
})
}
this.$emit("confirm", value)
}
}
},
methods: {
fieldChange(val, cnd) {
this.$set(cnd, "value", '')
this.$set(cnd, "fieldObj", this.fields.find(v => v.value == val))
},
doSubmit() {
this.dialogVisible = false
this.$emit("confirm", this.value)
},
flush() {
this.value = {
method: "AND",
conditions: [{}],
}
},
open(flush) {
if (flush || !this.value || !Object.keys(this.value)) {
this.flush()
}
this.dialogVisible = true
}
},
created() {
}
}
</script>
<style>
</style>
@@ -0,0 +1,86 @@
<template>
<el-select v-model="value" :placeholder="placeholder" @change="onChange" :clearable="clearable" :style="style"
:multiple="multiple"
:size="size">
<el-option
v-for="item in options"
:key="item[option_value]"
:label="item[option_label]"
:value="item[option_value]">
</el-option>
</el-select>
</template>
<script>
module.exports = {
props: {
value: {type: String},
code: {
type: String,
default: ""
},
option_value: {
type: String,
default: "code"
},
option_label: {
type: String,
default: "name"
},
style: {
type: String,
default: ""
},
size: {
type: String,
default: ""
},
placeholder: {
type: String,
default: "请选择"
},
clearable: {
type: Boolean,
default: true
},
multiple: {
type: Boolean,
default: false
},
},
model: {
prop: 'value',
event: 'change'
},
data() {
return {
options: []
}
},
watch: {
code(val) {
this.flushOptions()
}
},
methods: {
onChange(val) {
this.$emit("change", val)
},
async flushOptions() {
if (!this.code) {
this.options = []
return
}
this.options = await getDictOptions(this.code)
},
},
created() {
this.flushOptions()
}
}
</script>
<style>
</style>
@@ -0,0 +1,83 @@
<template>
<div>
<el-drawer
title="我是标题" size="78%"
:visible.sync="userScopeDialog"
:append-to-body="true"
:with-header="false">
<div style="padding: 0px 16px;" class="clearfix">
<el-button icon="el-icon-back" style="font-size: 16px" type="text"
@click="userScopeDialog = false">返回
</el-button>
</div>
<guava>
<el-tabs tab-position="top" v-model="activeName" @tab-click="handleClick">
<el-tab-pane label="人员设置" name="1">
<template>
<user-scope ref="userScope" @group_change="group_change"
:group_id.sync="groupId"></user-scope>
</template>
</el-tab-pane>
<el-tab-pane label="人员调整" name="2">
<user-data-scope
@group_change="group_change"
ref="userDataScope"
></user-data-scope>
</el-tab-pane>
</el-tabs>
</guava>
</el-drawer>
</div>
</template>
<script>
module.exports = {
props: {},
model: {},
mixins: [initTableMixins],
data() {
return {
groupId: "",
userScopeDialog: false,
activeName: '1',
}
},
methods: {
handleClick() {
if (this.activeName === "2") {
this.$refs.userDataScope.getActivityGroup()
} else {
this.$refs.userScope.getActivityGroup()
}
},
group_change() {
this.$emit('group_change')
}
},
components: {
'user-data-scope': httpVueLoader('/components/plugins/UserDataScope.vue'),
'user-scope': httpVueLoader('/components/plugins/UserScope.vue'),
},
watch: {
'groupId': {
async handler(newVal) {
this.$emit("update:group_id", newVal)
},
},
},
mounted() {
},
}
</script>
@@ -0,0 +1,81 @@
<template>
<el-select v-model="model" :clearable="clearable" :multiple="multiple" :placeholder="placeholder" :size="size"
:style="style"
@change="onChange">
<el-option
v-for="item in options"
:key="item[value]"
:label="item[label]"
:value="item[value]">
</el-option>
</el-select>
</template>
<script>
module.exports = {
props: {
model: {type: String},
enum: {type: String},
value: {
type: String
},
label: {
type: String
},
style: {
type: String,
default: ""
},
size: {
type: String,
default: ""
},
placeholder: {
type: String,
default: "请选择"
},
clearable: {
type: Boolean,
default: true
},
multiple: {
type: Boolean,
default: false
},
},
model: {
prop: 'model',
event: 'change'
},
data() {
return {
options: []
}
},
watch: {
enum(val) {
this.flushOptions()
}
},
methods: {
onChange(val) {
this.$emit("change", val)
},
async flushOptions() {
if (!this.enum) {
this.options = []
return
}
this.options = await getEnumOptions(this.enum)
},
},
created() {
this.flushOptions()
}
}
</script>
<style>
</style>
@@ -0,0 +1,188 @@
<template>
<div>
<vi-title2 title="分段设置&emsp;&emsp;提示:如分工会人数在0-20人的,分配5个名额;21-50人,分配10个名额">
<template #func>
<el-button size="small" type="primary" @click="unionLimitQuickSetting">
应用分段设置
</el-button>
</template>
</vi-title2>
<el-row v-for="(item,index) in unionUserNumCalc" :gutter="20" class="mb5">
<el-col :span="7">
<el-input-number v-model="item.startNum" :precision="0" :step="1" :min="1" placeholder="请输入最小人数"
style="width: 100%"></el-input-number>
</el-col>
<el-col :span="7">
<el-input-number v-model="item.endNum" :precision="0" :step="1" :min="1" placeholder="请输入最大人数"
style="width: 100%"></el-input-number>
</el-col>
<el-col :span="6">
<el-input-number v-model="item.resultNum" :precision="0" :step="1" :min="1" placeholder="请输入限制人数"
style="width: 100%"></el-input-number>
</el-col>
<el-col :span="4" class="text-right">
<el-button icon="el-icon-plus" @click="unionUserNumCalc.push({})"></el-button>
<el-button icon="el-icon-minus" @click="unionUserNumCalc.splice(index,1)"
:disabled="unionUserNumCalc.length===1"></el-button>
</el-col>
</el-row>
<el-row class="mt10">
<div v-for="(item,index) in unionUserNumCalcTips" class="text-danger">
<span class="mr10">({{index+1}}).</span> {{item}}
</div>
</el-row>
<vi-title2 title="比例设置" class="mt20">
<template #func>
一键比例
<el-input-number v-model="unionUserNumOneKeyRatio" :precision="0" :step="1" :min="0"
placeholder="请输入一键比例"
size="small"
:max="100"></el-input-number>
<el-button size="small" type="primary" @click="applyScaleSettings" class="ml5">应用比例设置</el-button>
</template>
</vi-title2>
<el-table :data="union_limit" max-height="500px">
<el-table-column prop="unionname" label="分工会"></el-table-column>
<el-table-column prop="teacherCount" label="人数"></el-table-column>
<el-table-column prop="ratio" label="比例(%)">
<template slot-scope="scope">
<el-input-number v-model="scope.row.ratio" @change="(val) => ratioChange(val, scope.$index)" :precision="0" :step="1" :min="0" :max="100"></el-input-number>
</template>
</el-table-column>
<el-table-column prop="limitCount" label="分配人数">
<template scope="{row}">
<el-input-number v-model="row.limitCount" :precision="0" :step="1" :min="0"
:max="row.teacherCount" @change="calSummaryCount"></el-input-number>
</template>
</el-table-column>
</el-table>
<el-row class="mt20" justify="end" type="flex">
<div class="text-danger" style="width: 100%;font-size: 18px;display: flex;align-items: center;font-weight: bold">分配总人数{{summaryCount}}</div>
<el-button @click="clearUnionLimit" type="danger">清空当前已分配</el-button>
</el-row>
</div>
</template>
<script>
module.exports = {
props: {
union_limit: {
type: Object, default: []
},
user_scope: {
type: String, default: ''
}
},
model: {
},
data() {
return {
unionUserNumCalc: [{}],
summaryCount: 0,
unionUserNumOneKeyRatio: null,
}
},
watch: {
union_limit: {
deep: true,
handler: function (value) {
this.$emit("update:union_limit", value)
}
}
},
methods: {
async clearUnionLimit() {
const confirm = await this.$confirm('确定要清空分工会人数限制吗, 是否继续?', '提示', {
confirmButtonText: '确定',
cancelButtonText: '取消',
type: 'warning'
})
if ('confirm' === confirm) {
this.union_limit = []
this.summaryCount = 0
this.unionUserNumOneKeyRatio = null
this.unionUserNumCalc = [{}]
await this.initData()
}
},
unionLimitQuickSetting() {
this.unionUserNumCalc.forEach((v, i) => {
const startNum = v.startNum
const endNum = v.endNum
const resultNum = v.resultNum
if (startNum > endNum) {
this.$message.warning('第' + (i + 1) + '行设置错误')
} else {
this.union_limit.forEach(x => {
if (x.teacherCount >= startNum && x.teacherCount <= endNum) {
x.limitCount = resultNum
}
})
this.calSummaryCount()
}
})
},
calSummaryCount() {
const array = this.union_limit
if (array && array.length > 0) {
this.summaryCount = array.reduce((prev, curr) => {
const union_limit = Number(curr.limitCount);
if (!isNaN(union_limit)) {
return prev + curr.limitCount;
} else {
return prev;
}
}, 0)
}
},
//应用比例设置
applyScaleSettings() {
this.union_limit.forEach(v => {
v.ratio = this.unionUserNumOneKeyRatio
if (v.ratio) {
v.limitCount = parseFloat((v.teacherCount * v.ratio / 100).toFixed(0))
}
})
this.calSummaryCount()
},
ratioChange(val, index) {
const v = this.union_limit[index]
v.limitCount = parseFloat((v.teacherCount * v.ratio / 100).toFixed(0))
this.calSummaryCount()
},
async initData() {
if (!this.union_limit || this.union_limit.length === 0) {
const resp = await $.get('/platform/vi/common/getUnionLimit', {activityScopeId: this.user_scope})
if (resp.code === 0) {
this.$set(this, 'union_limit', resp.data)
}
}
this.calSummaryCount()
}
},
computed: {
unionUserNumCalcTips() {
return this.unionUserNumCalc.map(v => {
return (v.startNum ? v.startNum : '?') + '-' + (v.endNum ? v.endNum : '?') + '人的分工会,限报' + (v.resultNum ? v.resultNum : '?') + '人'
})
},
},
created() {
this.initData()
}
}
</script>
<style scoped>
</style>
@@ -0,0 +1,766 @@
<template>
<div v-if="view" class="viewFile">
<div v-for="(file,index) in files" class="viewFileItem" title="点击查看" @click="showSource(file)">
<template v-if="resolvingShowByFileName(file.filename) == 1">
<el-image
:src="APP_DOMAIN + '/file_server/fileStreamPreview?id=' + file.id"
fit="cover"
style="width: 100%; height: 100%;"></el-image>
<!-- <img class="show-img" :src="getFileItemShowIcon(file.filepath)" :alt="file.filename"/>-->
</template>
<template v-else>
<svg aria-hidden="true">
<use :xlink:href="APP_DOMAIN + '/file_server/fileStreamPreview?id=' + file.id"></use>
</svg>
</template>
<div :title="file.filename" class="viewFileName">{{ file.filename }}</div>
</div>
</div>
<el-upload
v-else-if="card"
:limit="max"
:action="FILE_UPLOAD_ADDRESS"
:before-upload="beforeUpload"
:on-remove="handleRemove"
:on-success="onSuccess"
:file-list="fileList"
:on-exceed="handleExceed"
class="x100000"
drag
:on-preview="handlePreview"
multiple>
<i class="el-icon-upload"></i>
<div class="el-upload__text">将文件拖到此处<em>点击上传</em></div>
</el-upload>
<el-upload
v-else
:limit="max"
:action="FILE_UPLOAD_ADDRESS"
:before-upload="beforeUpload"
:on-remove="handleRemove"
:on-success="onSuccess"
:file-list="fileList"
:on-exceed="handleExceed"
:on-preview="handlePreview"
class="x100000"
multiple>
<el-button size="small" type="primary">点击上传</el-button>
</el-upload>
</template>
<script>
/**
* 文件类型解析
* @type {{isImg: wpUploadFileTypeResolve.isImg}}
*/
let fileTypeResolving = {
/**
* 是否是一张图片
*/
isImg: function (fileItem) {
return fileTypeResolving.resolvingByType(fileItem.type, /image\/(\w)*/)
},
/**
* 通过后缀验证图片
*/
isImgByName: function (fileItemName) {
let checkSuffixArray = ['jpg', 'png', 'jpeg', 'bmp', 'gif', 'webp', 'tif', 'svg', 'wmf'];
return fileTypeResolving.resolvingByName(fileItemName, checkSuffixArray)
},
/**
* 是否是视频
*/
isVideo: function (fileItem) {
return fileTypeResolving.resolvingByType(fileItem.type, /video\/(\w)*/)
},
/**
* 通过后缀验证图片
*/
isVideoByName: function (fileItemName) {
let checkSuffixArray = ['mp4', 'Ogg', 'webm'];
return fileTypeResolving.resolvingByName(fileItemName, checkSuffixArray)
},
/**
* 是否是音频
*/
isAudio: function (fileItem) {
return fileTypeResolving.resolvingByType(fileItem.type, /audio\/(\w)*/)
},
/**
* 通过后缀验证图片
*/
isAudioByName: function (fileItemName) {
let checkSuffixArray = ['mp3', 'ogg', 'wav'];
return fileTypeResolving.resolvingByName(fileItemName, checkSuffixArray)
},
/**
* 是否是doc文件
*/
isDoc: function (fileItemName) {
let checkSuffixArray = ['doc', 'docx', 'dot', 'dotx'];
return fileTypeResolving.resolvingByName(fileItemName, checkSuffixArray);
},
/**
* 是否是excel文件
*/
isExcel: function (fileItemName) {
let checkSuffixArray = ['xls', 'xlsx', 'csv', 'xlt', 'xltx'];
return fileTypeResolving.resolvingByName(fileItemName, checkSuffixArray);
},
/**
* 是否是PPT文件
*/
isPPT: function (fileItemName) {
let checkSuffixArray = ['ppt', 'pptx', 'pot', 'potx', 'odp'];
return fileTypeResolving.resolvingByName(fileItemName, checkSuffixArray);
},
/**
* 是否是Pdf文件
*/
isPdf: function (fileItemName) {
let checkSuffixArray = ['pdf'];
return fileTypeResolving.resolvingByName(fileItemName, checkSuffixArray);
},
/**
* 是否是压缩文件
* @param fileItem
* @returns {boolean}
*/
isZip: function (fileItemName) {
let checkSuffixArray = ['zip', '7z', 'war', 'tar', 'rar', 'jar', 'zipx', 'zix', 'zoo'];
return fileTypeResolving.resolvingByName(fileItemName, checkSuffixArray);
},
isWeb: function (fileItemName) {
let checkSuffixArray = ['html', 'htm'];
return fileTypeResolving.resolvingByName(fileItemName, checkSuffixArray);
},
isTxt: function (fileItemName) {
let checkSuffixArray = ['txt'];
return fileTypeResolving.resolvingByName(fileItemName, checkSuffixArray);
},
isPsd: function (fileItemName) {
let checkSuffixArray = ['psd'];
return fileTypeResolving.resolvingByName(fileItemName, checkSuffixArray);
},
isCad: function (fileItemName) {
let checkSuffixArray = ['cad'];
return fileTypeResolving.resolvingByName(fileItemName, checkSuffixArray);
},
isIso: function (fileItemName) {
let checkSuffixArray = ['iso'];
return fileTypeResolving.resolvingByName(fileItemName, checkSuffixArray);
},
isExe: function (fileItemName) {
let checkSuffixArray = ['exe'];
return fileTypeResolving.resolvingByName(fileItemName, checkSuffixArray);
},
/**
* 根据文件类型来解析
* @param fileType 文件类型
* @param checkTypeModel 文件类型模型,如:image\/(\w)*
* @returns {boolean}
*/
resolvingByType: function (fileType, checkTypeModel) {
if (checkTypeModel.test(fileType)) {
return true;
}
return false;
},
/**
* 根据名字和名字后缀名来验证文件
* @param fileName 文件名
* @param checkSuffixArray 文件类型包含的后缀
*/
resolvingByName: function (fileName, checkSuffixArray) {
let suffixName = wpUploadFileTools.getSuffixNameByFileName(fileName);
// 名字是否有效
if (!wpUploadDataValid.isValidStr(suffixName)) {
// 无效直接返回false
return false;
}
suffixName = suffixName.trim();
suffixName = suffixName.toLowerCase();
if (checkSuffixArray.indexOf(suffixName) != -1) {
return true;
}
return false;
}
}
/**
* 文件工具
* @type {{}}
*/
let wpUploadFileTools = {
/**
* 获取文件显示模版
* @param fileItem
*/
wapFileItemShow: function (fileItem) {
return wpUploadFileTools.wapFileItemShowBase(fileItem, false);
},
/**
* 包装已上传的文件列表
*/
wapFileItemShowWithUpload(uploadFile) {
return wpUploadFileTools.wapFileItemShowBase(uploadFile, true);
},
/**
* 获取文件显示的基本操作
*/
wapFileItemShowBase(fileItem, isUploaded = false) {
let fileName = "";
let suffix = "";
let show = "";
let showIcon = "";
if (!isUploaded) {
fileName = fileItem.name;
suffix = wpUploadFileTools.getSuffixNameByFileName(fileName);
show = wpUploadFileTools.resolvingShow(fileItem);
showIcon = wpUploadFileShowResolving.getFileItemShowIcon(show, fileItem, false);
} else {
fileName = fileItem.name ? fileItem.name : wpUploadFileTools.resolvingUrlFileName(fileItem.url);
let fileNameGetOFuRL = wpUploadFileTools.resolvingUrlFileName(fileItem.url);
suffix = wpUploadFileTools.getSuffixNameByFileName(fileNameGetOFuRL);
show = wpUploadFileTools.resolvingShowByFileName(fileNameGetOFuRL);
showIcon = wpUploadFileShowResolving.getFileItemShowIcon(show, fileItem.url, true);
}
let fileItemShow = {
// 文件的id
id: wpUploadFileTools.uuid(),
// 文件对象
file: null,
// 文件的类型
type: null,
// 文件的大小
size: null,
// 文件的名字
name: fileName,
// 文件地址
url: null,
// 后缀
suffix: suffix,
// 显示的类型
show: show,
// 显示的图标或者图片地址
showIcon: showIcon,
// 显示进度条
processStatus: {
show: false,
width: 0,
isFail: false
},
// 文件来源,0选择文件上传,1回显文件
fileSource: 0,
// 状态0未上传,失败也会转到0,1正在上传,2已经上传
status: 0,
// 上传文件的描述
fileDes: null
}
if (!isUploaded) {
// 如果非选择文件下面三个属性为null
fileItemShow.file = fileItem;
fileItemShow.type = fileItem.type;
fileItemShow.size = fileItem.size;
} else {
// 文件描述
fileItemShow.status = 2;
fileItemShow.fileDes = fileItem;
fileItemShow.fileSource = 1;
fileItemShow.url = fileItem.url;
}
return fileItemShow;
},
/**
* 解析URL的文件名字
*/
resolvingUrlFileName: function (fileUrl) {
let index = fileUrl.lastIndexOf("/");
if (index <= 0) {
index = fileUrl.lastIndexOf("\\");
}
index = index + 1;
let fileName = fileUrl.substring(index, fileUrl.length);
return fileName;
},
/**
* 获取文件名后缀
* @param fileName 文件名全名
* */
getSuffixNameByFileName: function (fileName) {
let str = fileName;
let index = str.lastIndexOf(".");
if (index < 0) {
return "";
}
let pos = index + 1;
return str.substring(pos, str.length);
},
/**
* 解析显示类型
* @param fileItem 文件
* @returns {number}
*/
resolvingShow: function (fileItem) {
// 默认0普通文件
let showResult = 0;
if (wpUploadFileTypeResolving.isImg(fileItem)) {
showResult = 1;
} else if (wpUploadFileTypeResolving.isVideo(fileItem)) {
showResult = 2;
} else if (wpUploadFileTypeResolving.isAudio(fileItem)) {
showResult = 3;
} else if (wpUploadFileTypeResolving.isDoc(fileItem.name)) {
showResult = 4;
} else if (wpUploadFileTypeResolving.isExcel(fileItem.name)) {
showResult = 5;
} else if (wpUploadFileTypeResolving.isPPT(fileItem.name)) {
showResult = 6;
} else if (wpUploadFileTypeResolving.isPdf(fileItem.name)) {
showResult = 7;
} else if (wpUploadFileTypeResolving.isZip(fileItem.name)) {
showResult = 8;
} else if (wpUploadFileTypeResolving.isWeb(fileItem.name)) {
showResult = 9;
} else if (wpUploadFileTypeResolving.isTxt(fileItem.name)) {
showResult = 10;
} else if (wpUploadFileTypeResolving.isPsd(fileItem.name)) {
showResult = 11;
} else if (wpUploadFileTypeResolving.isCad(fileItem.name)) {
showResult = 12;
} else if (wpUploadFileTypeResolving.isIso(fileItem.name)) {
showResult = 13;
} else if (wpUploadFileTypeResolving.isExe(fileItem.name)) {
showResult = 14;
}
return showResult
},
/**
* 解析显示类型
* @param fileItem 文件
* @returns {number}
*/
resolvingShowByFileName: function (fileItemName) {
// 默认0普通文件
let showResult = 0;
if (wpUploadFileTypeResolving.isImgByName(fileItemName)) {
showResult = 1;
} else if (wpUploadFileTypeResolving.isVideoByName(fileItemName)) {
showResult = 2;
} else if (wpUploadFileTypeResolving.isAudioByName(fileItemName)) {
showResult = 3;
} else if (wpUploadFileTypeResolving.isDoc(fileItemName)) {
showResult = 4;
} else if (wpUploadFileTypeResolving.isExcel(fileItemName)) {
showResult = 5;
} else if (wpUploadFileTypeResolving.isPPT(fileItemName)) {
showResult = 6;
} else if (wpUploadFileTypeResolving.isPdf(fileItemName)) {
showResult = 7;
} else if (wpUploadFileTypeResolving.isZip(fileItemName)) {
showResult = 8;
} else if (wpUploadFileTypeResolving.isWeb(fileItemName)) {
showResult = 9;
} else if (wpUploadFileTypeResolving.isTxt(fileItemName)) {
showResult = 10;
} else if (wpUploadFileTypeResolving.isPsd(fileItemName)) {
showResult = 11;
} else if (wpUploadFileTypeResolving.isCad(fileItemName)) {
showResult = 12;
} else if (wpUploadFileTypeResolving.isIso(fileItemName)) {
showResult = 13;
} else if (wpUploadFileTypeResolving.isExe(fileItemName)) {
showResult = 14;
}
return showResult
},
/**
* 生成UUID
* @returns {string}
*/
uuid: function () {
let str = wpUploadFileTools.uuidFull();
str = str.replace(/-/g, "");
return str;
},
uuidFull() {
let s = []
let hexDigits = "0123456789abcdef"
for (var i = 0; i < 36; i++) {
s[i] = hexDigits.substr(Math.floor(Math.random() * 0x10), 1)
}
s[14] = "4"
s[19] = hexDigits.substr((s[19] & 0x3) | 0x8, 1)
s[8] = s[13] = s[18] = s[23] = "-"
let uuid = s.join("")
return uuid
},
/**
* 禁止某个dom的某个事件
*/
disableObjEvent(domObj, eventName) {
domObj.addEventListener(eventName, function (e) {
e.preventDefault();
})
}
}
/**
* 数据验证工具
* @type {{isValid: wpUploadDataValid.isValid}}
*/
let wpUploadDataValid = {
isValid: function (obj) {
if (undefined === obj || null === obj) {
return false;
}
return true;
},
isValidStr: function (str) {
let isValidObj = wpUploadDataValid.isValid(str);
if (!isValidObj) {
return isValidObj;
}
str = str.trim();
if ("" == str || '' == str) {
return false;
}
return true;
},
isValidArray(array) {
if (null == array || array == undefined || array.length <= 0) {
return false;
}
return true;
}
}
module.exports = {
props: {
files: Array,
type: {
type: Array,
default: ['jpg', 'jpeg', 'png', 'doc', 'docx', 'xls', 'xlsx', 'pdf']
},
max: {
type: Number,
default: 5
},
max_size: {
type: Number,
default: 20 * 1024 * 1024
},
view: {
type: Boolean,
default: false
},
card: {
type: Boolean,
default: false
},
del: {
type: Boolean,
default: true
}
},
data() {
return {
fileList: []
}
},
watch: {
files(val) {
this.updateFileList(val)
}
},
methods: {
/**
* 查看资源
*/
showSource(showItem) {
const show = this.resolvingShowByFileName(showItem.filename)
if (show == 1 || show == 2 || show == 3) {
const fileArray = this.files.filter(item => {
const show = this.resolvingShowByFileName(item.filename)
return show === 1 || show === 2 || show === 3
})
let index = 0
if(fileArray && fileArray.length > 0) {
const f = fileArray.findIndex(o => o.id === showItem.id)
index = f !== -1 ? f : 0
}
const vv = new Viewer($(".viewFile").clone()[0], {
url: 'src',
initialViewIndex: index,
hide:function(){ //在图片消失的时候销毁viewer
vv.destroy()
}
})
vv.show()
} else if (show == 4 || show == 5 || show == 7) {
preview(showItem.filename, showItem.id)
}
},
/**
* 解析显示类型
* @param fileItem 文件
* @returns {number}
*/
resolvingShowByFileName(fileItemName) {
// 默认0普通文件
let showResult = 0;
if (fileTypeResolving.isImgByName(fileItemName)) {
showResult = 1;
} else if (fileTypeResolving.isVideoByName(fileItemName)) {
showResult = 2;
} else if (fileTypeResolving.isAudioByName(fileItemName)) {
showResult = 3;
} else if (fileTypeResolving.isDoc(fileItemName)) {
showResult = 4;
} else if (fileTypeResolving.isExcel(fileItemName)) {
showResult = 5;
} else if (fileTypeResolving.isPPT(fileItemName)) {
showResult = 6;
} else if (fileTypeResolving.isPdf(fileItemName)) {
showResult = 7;
} else if (fileTypeResolving.isZip(fileItemName)) {
showResult = 8;
} else if (fileTypeResolving.isWeb(fileItemName)) {
showResult = 9;
} else if (fileTypeResolving.isTxt(fileItemName)) {
showResult = 10;
} else if (fileTypeResolving.isPsd(fileItemName)) {
showResult = 11;
} else if (fileTypeResolving.isCad(fileItemName)) {
showResult = 12;
} else if (fileTypeResolving.isIso(fileItemName)) {
showResult = 13;
} else if (fileTypeResolving.isExe(fileItemName)) {
showResult = 14;
}
return showResult
},
/**
* 获取文件显示图标
* @param filePath
* @returns {string}
*/
getFileItemShowIcon(filePath) {
let showIcon = '';
switch (this.resolvingShowByFileName(filePath)) {
case 0:
showIcon = "#icon-yunpanlogo-3";
break;
// 图片
case 1:
showIcon = this.getImgShowIcon(filePath);
break;
// 视频
case 2:
showIcon = "#icon-yunpanlogo-6";
break;
// 音乐
case 3:
showIcon = "#icon-yunpanlogo-4";
break;
// doc
case 4:
showIcon = "#icon-yunpanlogo-2";
break;
// excel
case 5:
showIcon = "#icon-yunpanlogo-";
break;
// ppt
case 6:
showIcon = "#icon-yunpanlogo-1";
break;
// pdf
case 7:
showIcon = "#icon-yunpanlogo-12";
break;
// zip
case 8:
showIcon = "#icon-yasuobao";
break;
// web文件
case 9:
showIcon = "#icon-yunpanlogo-5";
break;
// txt文件
case 10:
showIcon = "#icon-yunpanlogo-7";
break;
// PSD
case 11:
showIcon = "#icon-yunpanlogo-10";
break;
// cad
case 12:
showIcon = "#icon-yunpanlogo-11";
break;
// ISO
case 13:
showIcon = "#icon-yunpanlogo-8";
break;
// 可执行
case 14:
showIcon = "#icon-yunpanlogo-9";
break;
// 普通文件
default:
showIcon = "#icon-yunpanlogo-3";
}
return showIcon;
},
/**
* 获取图片的显示图标
* @param fileItem
* @returns {string|*}
*/
getImgShowIcon(fileItem) {
return FILE_DOMAIN + fileItem;
},
updateFileList(val) {
if (!val || !val.length) {
this.fileList = []
return
}
this.fileList = val.map(v => {
return {data: v, uid: v.id, name: v.filename, status: 'success'}
})
},
change(fileList) {
this.$emit("update:files", fileList.map(v => v.data))
},
handleExceed(files, fileList) {
this.$message.warning(`当前限制选择 ${this.max} 个文件,本次选择了 ${files.length} 个文件,共选择了 ${files.length + fileList.length} 个文件`);
},
onSuccess(response, file, fileList) {
if (response.code === 0) {
const {data} = response
file.data = data
this.change(fileList)
} else {
this.$message.warning('文件上传失败')
}
},
beforeUpload(file) {
const type = this.type.includes(file.name.split('.')[1].toLowerCase());
const size = file.size < this.max_size;
if (!type) {
this.$message.warning(`上传文件只能是 ${this.type.map(v => v.toLowerCase()).join("/")} 格式!`);
}
if (!size) {
this.$message.warning(`上传文件大小不能超过 ${this.max_size / 1024 / 1024} MB!`);
}
return type && size;
},
async handleRemove(file, fileList) {
if (file.data) {
const {id} = file.data
if (this.del) {
const resp = await $.post(FILE_DELETE_ADDRESS, {id})
if (resp.code === 0) {
this.$message.success(resp.msg)
} else {
this.$message.warning(resp.msg)
}
}
this.change(fileList)
}
},
handlePreview(file) {
if (file.data) {
const {filename, id} = file.data
preview(filename, id)
}
},
},
created() {
this.updateFileList(this.files)
}
}
</script>
<style>
.viewFileName {
position: absolute;
bottom: 0;
left: 0;
width: 100%;
height: 24px;
line-height: 24px;
overflow: hidden;
text-overflow: ellipsis;
white-space: nowrap;
padding: 0 10px;
color: white;
background-color: rgb(160, 160, 160);
border-radius: 2px;
opacity: .95;
}
.viewFile {
position: relative;
display: flex;
width: 100%;
max-height: 256px;
flex-direction: row;
flex-wrap: wrap;
overflow-y: auto;
overflow-x: hidden;
}
.viewFileItem {
width: 118px;
height: 118px;
margin-right: 10px;
position: relative;
transition: all 500ms;
border-radius: 5px;
cursor: pointer;
margin-bottom: 10px;
}
.viewFileItem:hover {
background-color: rgb(230, 230, 230);
}
.viewFileItem img {
padding: 10px 10px;
}
.viewFileItem svg {
width: 100%;
height: 100%;
}
.x100000 .el-upload-dragger {
height: 120px;
width: 100%;
}
.x100000 .el-upload {
width: 100%;
text-align: left;
}
.el-upload-dragger .el-icon-upload {
font-size: 54px;
line-height: 0;
}
</style>
@@ -0,0 +1,180 @@
<template>
<div class="guava-main-content">
<transition-group appear mode="out-in" name="el-fade-in">
<!-- <transition name="el-fade-in-linear" appear mode="out-in">-->
<div v-show="v==='index'" key="index" class="transition-item">
<slot></slot>
</div>
<!-- </transition>-->
<el-card v-show="v==='edit'" key="edit" class="operation" shadow="never">
<template #header>
<el-row type="flex">
<el-col :span="12">
<el-button icon="el-icon-back" style="font-size: 16px" type="text" @click="v='index'">返回</el-button>
</el-col>
<el-col :span="12" class="text-right">
<slot name="edit_func"></slot>
</el-col>
</el-row>
</template>
<div>
<slot name="edit"></slot>
</div>
</el-card>
<el-card v-show="v==='view'" key="view" class="operation" shadow="never">
<template #header>
<el-button icon="el-icon-back" style="font-size: 16px" type="text" @click="v='index'">返回</el-button>
</template>
<slot name="view"></slot>
</el-card>
<el-card v-show="v==='public'" key="public" class="operation" shadow="never">
<div slot="header" class="clearfix">
<el-button icon="el-icon-back" style="font-size: 16px" type="text" @click="back()">返回
</el-button>
</div>
<div>
<slot name="public"></slot>
</div>
</el-card>
</transition-group>
<!-- <transition name="el-fade-in-linear" appear mode="out-in">-->
<!-- <div v-show="v==='index'" class="transition-item" key="index">-->
<!-- <slot></slot>-->
<!-- </div>-->
<!-- </transition>-->
<!-- <transition name="el-fade-in-linear" appear mode="in-out">-->
<!-- <el-card v-show="v==='edit'" class="operation" shadow="never" key="edit">-->
<!-- <template #header>-->
<!-- <el-row type="flex">-->
<!-- <el-col :span="12">-->
<!-- <el-button icon="el-icon-back" style="font-size: 16px" type="text" @click="v='index'">返回</el-button>-->
<!-- </el-col>-->
<!-- <el-col :span="12" class="text-right">-->
<!-- <slot name="edit_func"></slot>-->
<!-- </el-col>-->
<!-- </el-row>-->
<!-- </template>-->
<!-- <div>-->
<!-- <slot name="edit"></slot>-->
<!-- </div>-->
<!-- </el-card>-->
<!-- </transition>-->
<!-- <el-card v-show="v==='view'" class="operation" shadow="never" key="view">-->
<!-- <template #header>-->
<!-- <el-button icon="el-icon-back" style="font-size: 16px" type="text" @click="v='index'">返回</el-button>-->
<!-- </template>-->
<!-- <slot name="view"></slot>-->
<!-- </el-card>-->
<!-- <div v-show="v==='public'" class="transition-item transition-item2">-->
<!-- <el-card class="box-card v-box guava-card" shadow="never">-->
<!-- <div slot="header" class="clearfix">-->
<!-- <el-button icon="el-icon-back" style="font-size: 16px" type="text" @click="back()">返回-->
<!-- </el-button>-->
<!-- </div>-->
<!-- <div>-->
<!-- <slot name="public"></slot>-->
<!-- </div>-->
<!-- </el-card>-->
<!-- </div>-->
</div>
</template>
<script>
module.exports = {
props: {
name: {
type: String,
default: "el-zoom-in-top"
},
value: {
type: String,
default: 'index'
}
},
data() {
return {
v: 'index',
}
},
watch: {
v(newValue, oldValue) {
this.$emit('vchange', {newValue, oldValue})
this.$emit('input', newValue)
}
},
methods: {
index() {
this.v = 'index'
},
edit() {
this.v = 'edit'
},
view() {
this.v = 'view'
},
public() {
this.v = 'public'
},
back() {
this.v = 'index'
}
},
created() {
}
}
</script>
<style>
.guava-main-content {
padding: 10px;
background-color: #f6f6f6;
min-height: 100%;
}
.el-card__header {
padding: 5px 20px !important;
}
.operation {
min-height: calc(100vh - 70px) !important;
display: flex;
flex-direction: column;
}
.operation .el-card__body {
flex: auto;
}
.el-tabs--border-card {
box-shadow: unset !important;
}
/*.v-enter-active, .v-leave-active {*/
/* transition: all 0.5s;*/
/*}*/
/*.v-enter, .v-leave-to {*/
/* opacity: 0;*/
/*}*/
/*.v-leave, .v-enter-to {*/
/* opacity: 1;*/
/*}*/
</style>
@@ -0,0 +1,242 @@
<template>
<div class="component-upload-image">
<el-upload
:style="{'--box-width': width + 'px', '--box-height': height + 'px'}"
multiple
:action="FILE_UPLOAD_ADDRESS"
list-type="picture-card"
:on-success="handleUploadSuccess"
:before-upload="handleBeforeUpload"
:limit="limit"
:on-error="handleUploadError"
:on-exceed="handleExceed"
ref="imageUpload"
:on-remove="handleDelete"
:file-list="fileList"
:on-preview="handlePictureCardPreview"
:class="{hidePic: this.fileList.length >= this.limit}"
>
<i class="el-icon-plus"></i>
</el-upload>
<!-- 上传提示 -->
<div class="el-upload__tip" slot="tip" v-if="showTip">
请上传
<template v-if="fileSize"> 大小不超过 <b style="color: #f56c6c">{{ fileSize }}MB</b></template>
<template v-if="fileType"> 格式为 <b style="color: #f56c6c">{{ fileType.join("/") }}</b></template>
的文件
</div>
</div>
</template>
<script>
module.exports = {
name: "ImageUpload",
props: {
value: [String, Array],
// 图片数量限制
limit: {
type: Number,
default: 5,
},
// 大小限制(MB)
fileSize: {
type: Number,
default: 5,
},
// 文件类型, 例如['png', 'jpg', 'jpeg']
fileType: {
type: Array,
default: () => ["png", "jpg", "jpeg"],
},
// 是否显示提示
isShowTip: {
type: Boolean,
default: true
},
height: {
type: Number,
default: 100
},
width: {
type: Number,
default: 100
}
},
data() {
return {
dialogImageUrl: "",
dialogVisible: false,
hideUpload: false,
fileList: []
}
},
watch: {
value: {
immediate: true,
deep: true,
handler(val) {
if (val) {
let fff = []
fff = Array.isArray(val) ? [...val] : [val]
this.fileList = fff.map(v => {
return {
name: v,
url: CREATE_PREVIEW_URL(v)
}
})
}
}
}
},
computed: {
// 是否显示提示
showTip() {
return this.isShowTip && (this.fileType || this.fileSize);
},
},
methods: {
// 上传前loading加载
handleBeforeUpload(file) {
let isImg = false;
if (this.fileType.length) {
let fileExtension = "";
if (file.name.lastIndexOf(".") > -1) {
fileExtension = file.name.slice(file.name.lastIndexOf(".") + 1);
}
isImg = this.fileType.some(type => {
if (file.type.indexOf(type) > -1) return true;
if (fileExtension && fileExtension.indexOf(type) > -1) return true;
return false;
});
} else {
isImg = file.type.indexOf("image") > -1;
}
if (!isImg) {
this.$message.error(`文件格式不正确, 请上传${this.fileType.join("/")}图片格式文件!`);
return false;
}
if (this.fileSize) {
const isLt = file.size / 1024 / 1024 < this.fileSize;
if (!isLt) {
this.$message.error(`上传头像图片大小不能超过 ${this.fileSize} MB!`);
return false;
}
}
},
// 文件个数超出
handleExceed() {
this.$message.error(`上传文件数量不能超过 ${this.limit} 个!`);
},
// 上传成功回调
handleUploadSuccess(res, file) {
if (res.code === 0) {
if (this.limit === 1) {
this.$emit("input", res.data.filepath)
} else {
if (this.value && Array.isArray(this.value)) {
const v = [...this.value, res.data.filepath]
this.$emit("input", v)
} else {
this.$emit("input", [res.data.filepath])
}
}
} else {
this.$message.error(res.msg);
this.$refs.imageUpload.handleRemove(file);
}
},
// 删除图片
async handleDelete(file) {
const resp = await $.post(FILE_DELETE_ADDRESS, {id: file.name})
const findex = this.fileList.map(f => f.name).indexOf(file.name);
if (findex > -1) {
this.fileList.splice(findex, 1)
if (this.limit === 1) {
this.$emit("input", this.fileList.map(v => v.name).join('、'))
} else {
this.$emit("input", this.fileList.map(v => v.name))
}
}
/*if (resp.code === 0) {
this.$message.success(resp.msg)
const findex = this.fileList.map(f => f.name).indexOf(file.name);
if (findex > -1) {
this.fileList.splice(findex, 1)
if (this.limit === 1) {
this.$emit("input", this.fileList.map(v => v.name).join('、'))
} else {
this.$emit("input", this.fileList.map(v => v.name))
}
}
} else {
this.$message.warning(resp.msg)
}*/
},
// 上传失败
handleUploadError() {
this.$message.error("上传图片失败,请重试");
},
// 预览
handlePictureCardPreview(file) {
if (file.url) {
let image = new Image();
image.src = file.url
let viewer = new Viewer(image);
viewer.show();
} else {
viewImage(file.response.data.id)
}
}
}
}
</script>
<style scoped>
.component-upload-image .el-upload--picture-card {
width: var(--box-width, '100px') !important;
height: var(--box-height, '100px') !important;
display: flex;
align-items: center;
justify-content: center;
}
.el-upload--picture-card i {
font-size: 1em;
}
.el-upload-list--picture-card .el-upload-list__item {
width: var(--box-width, '100px');
height: var(--box-height, '100px');
}
.hidePic .el-upload--picture-card {
display: none !important;
}
.el-list-enter-active,
.el-list-leave-active {
transition: all 0s;
}
.el-list-enter, .el-list-leave-active {
opacity: 0;
transform: translateY(0);
}
.component-upload-image {
height: inherit;
}
.component-upload-image > div:nth-child(1) {
width: 100%;
height: 100%;
}
.el-upload__tip {
text-align: left;
}
</style>
@@ -0,0 +1,183 @@
<template>
<el-timeline>
<el-timeline-item timestamp="" placement="top">
<el-input placeholder="请输入内容" clearable v-model="pageForm.searchKeyword"
@keyup.enter.native="doSearch" style="width: 300px">
<el-select v-model="pageForm.searchName" slot="prepend" style="width: 80px;">
<el-option label="姓名" value="username"></el-option>
<el-option label="工号" value="loginname"></el-option>
</el-select>
</el-input>
<el-button type="primary" icon="el-icon-search" @click="doSearch"></el-button>
</el-timeline-item>
<el-timeline-item timestamp="" placement="top" v-if="is_ghxzzz">
<el-col :span="12">
<el-select v-model="pageForm.threeUnitId" clearable filterable
placeholder="请选择新科室"
style="width: 100%">
<el-option
v-for="item in threeUnits2"
:key="item.id"
:label="item.name"
:value="item.id">
</el-option>
</el-select>
</el-col>
</el-timeline-item>
<el-timeline-item timestamp="" placement="top">
<el-table :data="tableData" style="width: 100%" row-key="id"
v-loading="tableLoading" ref="table" class="vi-table"
@selection-change="handleSelectionChange">
<el-table-column type="selection" :reserve-selection="true"></el-table-column>
<el-table-column
align="center"
header-align="center"
v-for="column in columns"
show-overflow-tooltip
:sortable="column.sortable"
:label="column.label"
:prop="column.prop" :width="column.width">
</el-table-column>
</el-table>
<el-row class="el-pagination-container">
<el-pagination
@size-change="pageSizeChange"
@current-change="pageNumberChange"
:current-page="pageForm.pageNumber"
:page-size="pageForm.pageSize"
layout="total, prev, pager, next"
:total="pageForm.totalCount">
</el-pagination>
</el-row>
</el-timeline-item>
</el-timeline>
</template>
<script>
module.exports = {
props: {
value: {type: Array},
columns: {
type: Array,
default: [{
prop: 'loginname',
label: '工号',
}, {
prop: 'username',
label: '姓名',
}, {
prop: 'sex',
label: '性别',
}, {
prop: 'mobile',
label: '电话',
}, {
prop: 'threeUnitName',
label: '科室',
}, {
prop: 'unitname',
label: '单位',
}, {
prop: 'unionname',
label: '工会',
}]
},
union: {type: String},
is_ghxzzz: {type: Boolean},
page_size: {type: Number, default: 5},
sql_cnd: {
type: Array
}
},
model: {
prop: 'value',
event: 'change'
},
data() {
return {
unitMoveUnits: [],
threeUnits2: [],
tableData: [],
tableLoading: false,
selectUser: [],
pageForm: {
unionId: this.union,
sqlCnd: JSON.stringify(this.sql_cnd),
searchName: "username",
searchKeyword: "",
pageNumber: 1,
pageSize: this.page_size,
totalCount: 0,
pageOrderName: "",
pageOrderBy: ""
}
}
},
watch: {
value(val) {
}
},
methods: {
handleSelectionChange(val) {
this.selectUser = val
this.$emit("change", val.map(v => v.id))
},
doSearch() {
this.tableKey = new Date().getTime()
this.pageForm.pageNumber = 1
this.pageData()
},
pageOrder(column) {
this.pageForm.pageOrderName = column.prop;
this.pageForm.pageOrderBy = column.order;
this.pageData();
},
pageNumberChange(val) {
this.pageForm.pageNumber = val;
this.pageData();
},
pageSizeChange(val) {
this.pageForm.pageSize = val;
this.pageData();
},
pageData() {
this.tableLoading = true
$.post("/platform/member/change/mange/userPageData", this.pageForm, (data) => {
this.tableLoading = false
if (data.code == 0) {
this.tableData = data.data.list;
this.pageForm.totalCount = data.data.totalCount;
this.tableData.filter(v => this.value.includes(v.id) && !this.selectUser.some(x => x.id == v.id)).forEach(v => {
this.$refs.table.toggleRowSelection(v, true);
})
} else {
this.$message.error(data.msg);
}
}, "json");
},
async init() {
console.log(this.is_ghxzzz,this.sql_cnd)
this.doSearch()
this.selectUser = []
this.unitMoveUnits = await getUnits()
if (this.unitMoveUnits && this.unitMoveUnits.length > 0) {
this.pageForm.unitId = this.unitMoveUnits[0].id
this.threeUnits2 = await threeUnitsByUnionGroupOrUnitId(this.pageForm.unitId, null)
}
this.$refs.table.clearSelection();
},
},
created() {
}
}
</script>
<style>
</style>
@@ -0,0 +1,70 @@
<template>
<div>
<el-dialog
title="活动二维码"
:visible.sync="codeDialogVisible"
:close-on-click-modal="false"
width="40%">
<div style="width: 100%;">
<div id="qrcode" style="width: 70%;left: 0;right: 0;margin: auto"></div>
</div>
<span slot="footer" class="dialog-footer">
<el-button @click="codeDialogVisible = false" type="primary"> </el-button>
<!-- <el-button type="primary" @click="dwn('活动二维码')"> </el-button>-->
</span>
</el-dialog>
</div>
</template>
<script>
module.exports = {
props: {},
data() {
return {
codeDialogVisible: false,
}
},
methods: {
saveFile(data, filename) {
var save_link = document.createElementNS('http://www.w3.org/1999/xhtml', 'a');
save_link.href = data;
save_link.download = filename;
var event = document.createEvent('MouseEvents');
event.initMouseEvent('click', true, false, window, 0, 0, 0, 0, 0, false, false, false, false, 0, null);
save_link.dispatchEvent(event);
},
/*下载二维码*/
dwn(name) {
var type = 'png';
var dataurl = $("canvas").get(0).toDataURL('image/png').replace("image/png", "image/octet-stream");
var filename = name + '_' + (new Date()).getTime() + '.' + type;
this.saveFile(dataurl, filename);
},
openCode(url) {
this.codeDialogVisible = true
this.$nextTick(() => {
$("#qrcode").html("")
$("#qrcode").qrcode({ //设置css
render: "canvas", //二维码的生成方式
width: $("#qrcode").width(), //生成二维码的宽度
height: $("#qrcode").width(), //生成二维码的高度
text: APP_DOMAIN + url,
correctLevel: 3 //容错级别,默认为2,最高为3,为了让用户扫码最快,容错级别应当设为最低
});
})
console.log(APP_DOMAIN + url)
},
}
}
</script>
<style scoped>
</style>
@@ -0,0 +1,502 @@
<template>
<div>
<el-card shadow="never">
<el-form ref="form" label-width="80px">
<el-card v-for="(s,idx) in subject" :key="s.id" class="item" shadow="hover">
<!-- <el-form-item :label="(s.subjectType==='radio'?'(单选)':'(多选)')+ (idx+1)+'.'" prop="subjectName">-->
<el-form-item label="" prop="subjectName">
<div class="s-title-wrap">
<el-row align="middle" style="width: 100%" type="flex">
<el-col :xl="20"
style="border: 1px dashed rgb(217, 217, 217);border-radius:6px;display: flex;align-items: center;">
<el-input v-model="s.subjectName" class="text-input"
data-type="subject"></el-input>
</el-col>
<el-col :xl="2" style="text-align: center"></el-col>
<el-col :xl="2" style="text-align: center">
<div class="option-delete">
<el-button circle
icon="el-icon-delete"
size="mini" type="danger"
@click="subject.splice(idx,1)"></el-button>
</div>
</el-col>
</el-row>
</div>
<div class="s-options-list" style="margin-top: 10px;">
<el-table :data="s.options" border>
<el-table-column
align="center"
header-align="center"
label="类型"
>
<template slot-scope="{row}">
<el-select v-model="row.optionType" placeholder="请选择"
@change="optionTypeChange(row)">
<el-option
v-for="item in typeOptions"
:key="item"
:label="item"
:value="item">
</el-option>
</el-select>
</template>
</el-table-column>
<el-table-column
align="center"
header-align="center"
label="福利名称"
>
<template slot-scope="{row}">
<div
style="border: 1px dashed rgb(217, 217, 217);border-radius:6px;display: flex;align-items: center;padding-left: 10px;">
<i v-if="s.subjectType==='radio'" class="fa fa-circle-o"
style="cursor: pointer"></i>
<i v-else-if="s.subjectType==='checkBox'" class="fa fa-square-o"
style="cursor: pointer"></i>
<template v-if="row.optionType==='套餐'">
<el-input v-model="row.optionName" autosize
class="text-input"
data-type="option"
></el-input>
</template>
<template v-if="row.optionType==='提货券'">
<el-select v-model="row.optionNameId" placeholder="请选择"
@change="optionNameIdChange(row)">
<el-option
v-for="item in shoppingTypeOptions"
:key="item.id"
:disabled="item.disabled"
:label="item.shoppingName"
:value="item.id">
</el-option>
</el-select>
</template>
</div>
</template>
</el-table-column>
<el-table-column
align="center"
header-align="center"
label="排序" width="120px">
<template slot-scope="{row}">
<div
style="border: 1px dashed rgb(217, 217, 217);border-radius:6px;display: flex;align-items: center;padding-left: 10px;">
<el-input v-model="row.optionSort" autosize
class="text-input"
data-type="option"
></el-input>
</div>
</template>
</el-table-column>
<el-table-column
align="center"
header-align="center"
label="图片"
width="200px"
>
<template slot-scope="{row,$index}">
<div @click="uploadClick(idx,$index)">
<el-upload :action="FILE_UPLOAD_ADDRESS" :on-success="onFileSuccess"
:show-file-list="false" class="avatar-uploader">
<div v-if="row.imgUrl" style="position: relative">
<img :src="FILE_STREAM_PREVIEW_ADDRESS+'?id='+row.imgUrl" class="avatar">
<div @click.stop="closePopover(row)">
<i class="el-icon-delete avatar-delete"></i>
</div>
</div>
<!-- <img :src="FILE_STREAM_PREVIEW_ADDRESS+'?id='+row.imgUrl" class="avatar">-->
<i v-else class="el-icon-plus avatar-uploader-icon"></i>
</el-upload>
<!-- <el-popover
placement="top-start"
width="200"
>
<img :src="FILE_STREAM_PREVIEW_ADDRESS+'?id='+row.imgUrl" style="width: 100%;height: 150px">
<el-button size="mini" style="margin-top: 10px;width: 100%;" type="danger"
@click="closePopover(row)">
删除
</el-button>
<img v-if="row.imgUrl" slot="reference" :src="FILE_STREAM_PREVIEW_ADDRESS+'?id='+row.imgUrl"
style="width: 40px;height: 40px">
</el-popover>-->
</div>
</template>
</el-table-column>
<el-table-column align="center"
header-align="center"
label="说明"
width="100px">
<template slot-scope="scope">
<el-link type="primary"
@click="openDescRichText(scope.row.description,idx,scope.$index)">编辑说明
</el-link>
</template>
</el-table-column>
<el-table-column
align="center"
header-align="center"
label="默认值"
width="100px">
<template slot-scope="{row,$index}">
<el-checkbox v-model="row.isSystemDefault"
@change="(val,event)=>{systemDefaultChange(idx,$index,val)}"
></el-checkbox>
</template>
</el-table-column>
<el-table-column
align="center"
header-align="center"
label="没选系统自动分配"
width="200px">
<template slot-scope="{row,$index}">
<el-checkbox v-model="row.isDefaultOption"
@change="(val,event)=>{defaultOptionChange(idx,$index,val)}"
></el-checkbox>
</template>
</el-table-column>
<el-table-column
align="center"
header-align="center"
label="操作"
width="100px"
>
<template slot-scope="{row,$index}">
<div class="option-delete">
<el-button circle
icon="el-icon-delete"
size="mini" type="danger"
@click="deleteRow(s.options,row,$index)"></el-button>
</div>
</template>
</el-table-column>
</el-table>
<div class="s-operation">
<el-button size="small" type="primary"
@click="s.options.push({optionType:'套餐',optionNameId:'',optionName:'福利'+(s.options.length+1),optionSort:s.options.length+1,imgUrl:null})">
添加福利
</el-button>
</div>
</div>
</el-form-item>
</el-card>
</el-form>
<!-- <div class="text-center">-->
<!-- <el-button type="primary" size="small" @click="addSubject('radio')">添加单选题</el-button>-->
<!-- <el-button type="primary" size="small" @click="addSubject('checkBox')">添加多选题</el-button>-->
<!-- </div>-->
</el-card>
<el-dialog
:close-on-click-modal="false"
:visible.sync="richTextDialog"
title="编辑说明"
:append-to-body="true"
width="60%">
<div id="descRichText">
</div>
<span slot="footer" class="dialog-footer">
<el-button @click="richTextDialog = false"> </el-button>
<el-button type="primary" @click="getRichText"> </el-button>
</span>
</el-dialog>
</div>
</template>
<script>
let questionRichTextEditor = null
module.exports = {
components: {
vuedraggable: window.vuedraggable,
},
watch: {
subject(val) {
console.log(val)
}
},
props: {
subject: {
type: Array,
default: []
}
},
data() {
return {
typeOptions: ["套餐", "提货券"],
shoppingTypeOptions: null,
richTextDialog: false,
subjectIndex: 0,
optionIndex: 0,
imgPopover: false,
//题目列表
// subject: [
// {
// subjectName: '题目1',
// subjectType: 'radio',
// defaultOption: null,
// options: [
// {
// optionName: '选项1',
// imgUrl: '/r809h67mpsiulphfg1coehd5v3.jpg'
// },
// {
// optionName: '选项2',
// imgUrl: '/r809h67mpsiulphfg1coehd5v3.jpg'
// }
// ]
// }
// ],
idx: null,
oidx: null
}
},
methods: {
deleteRow(options, row, index) {
options.splice(index, 1)
const shoppingTypeOption = this.shoppingTypeOptions.find(v => v.id === row.optionNameId)
shoppingTypeOption.disabled = false
},
optionTypeChange(row) {
this.optionNameIdChange()
row.optionNameId = null
row.optionName = null
},
optionNameIdChange(row) {
if (row) {
row.optionName = this.shoppingTypeOptions.find(v => v.id === row.optionNameId).shoppingName
}
const optionNameIds = this.subject[0].options.map(v => v.optionNameId)
this.shoppingTypeOptions.forEach(v => {
v.disabled = optionNameIds.includes(v.id)
})
this.$forceUpdate()
},
addSubject(type) {
let subject = {
subjectName: '题目' + (this.subject.length + 1),
subjectType: type,
options: [
{optionName: '选项一', imgUrl: null},
{optionName: '选项一', imgUrl: null}
]
}
this.subject.push(subject)
},
onFileSuccess(response, file, fileList) {
const {data} = response
this.subject[this.idx].options[this.oidx].imgUrl = data.filepath
// this.$set()
this.$forceUpdate()
// this.subject[this.idx].options[this.oidx].optionName = data.filepath
},
uploadClick(idx, oidx) {
this.idx = idx
this.oidx = oidx
},
closePopover(o) {
const popovers = document.getElementsByClassName('el-popover')
for (let i = 0; i < popovers.length; i++) {
popovers[i].style.display = 'none'
}
o.imgUrl = null
},
defaultOptionChange(idx, oidx, val) {
const subject = this.subject[idx]
const {subjectType} = subject
if (val) {
// subject.options.forEach(v => v.isDefaultOption = false)
subject.options[oidx].isDefaultOption = true
}
},
systemDefaultChange(idx, oidx, val) {
console.log(2)
const subject = this.subject[idx]
const {subjectType} = subject
if (val) {
subject.options.forEach(v => v.isSystemDefault = false)
subject.options[oidx].isSystemDefault = true
}
},
validate(fn) {
const that = this
// return new Promise((resolve, reject) => {
// const s = that.formData.subject.some(v => {
// if (!v.subjectName) return true
// return v.options.some(x => {
// if (!x.optionName) return true
// })
// })
// if (s) reject(false)
// resolve(true)
// })
if (this._validate()) {
return false
}
return true
},
_validate() {
return this.subject.some(v => {
if (!v.subjectName) return true
return v.options.some(x => {
if (!x.optionName) return true
})
})
},
openDescRichText(richText, sIdx, oIdx) {
this.richTextDialog = true
this.subjectIndex = sIdx
this.optionIndex = oIdx
this.$nextTick(() => {
/*if (questionRichTextEditor == null) {
questionRichTextEditor = new wangEditor('#descRichText')
questionRichTextEditor.create()
}
console.log(richText)
questionRichTextEditor.txt.clear()
questionRichTextEditor.txt.html(richText)*/
$("#descRichText").html("")
questionRichTextEditor = new wangEditor("#descRichText")
questionRichTextEditor.config.onchange = (html) => {
richText = (html ? html : "")
}
questionRichTextEditor.config.uploadImgShowBase64 = true
questionRichTextEditor.create()
if (richText) {
questionRichTextEditor.txt.html(richText)
}
})
},
getRichText() {
// console.log(this.subject[this.subjectIndex]['options'][this.optionIndex])
this.subject[this.subjectIndex]['options'][this.optionIndex].description = questionRichTextEditor.txt.html()
this.richTextDialog = false
},
async getShoppingType() {
const resp = await $.get("/platform/shoppingType/apply/getShoppingType", {typeName: "商超"})
this.shoppingTypeOptions = resp.data
}
},
created() {
this.getShoppingType()
}
}
</script>
<style scoped>
.avatar-uploader .el-upload {
border: 1px dashed #d9d9d9;
border-radius: 6px;
cursor: pointer;
position: relative;
overflow: hidden;
/* width: 40px;
height: 40px;*/
/*line-height: 40px;*/
}
.avatar-uploader .el-upload:hover {
border-color: #409EFF;
}
.avatar-uploader-icon {
font-size: 14px;
color: #8c939d;
width: 40px;
height: 40px;
line-height: 40px;
text-align: center;
}
.el-upload el-upload--text {
width: 100px;
height: 100px;
}
.avatar {
width: 100px;
height: 80px;
display: block;
}
/*被拖拽对象的样式*/
.item {
padding: 6px;
background-color: #FFF;
border: solid 1px #eee;
margin-bottom: 10px;
cursor: move;
}
.item:hover {
/*background-color: #f1f1f1;*/
cursor: move;
}
/*选中样式*/
.chosen {
border: solid 1px #3089dc !important;
}
.s-title-wrap {
display: flex;
width: 100%;
overflow: hidden;
word-break: break-word;
white-space: nowrap;
}
.s-operation {
display: flex;
flex-wrap: wrap;
justify-content: start;
padding: 5px 0;
}
.s-operation > span {
display: flex;
height: 22px;
cursor: pointer;
color: #2672ff;
align-items: center;
justify-content: center;
}
.option-delete {
width: 80px;
text-align: center;
}
.s-operation i {
margin-right: 10px;
}
.text-input > input, .text-input > textarea {
resize: none;
overflow: hidden;
/*border: 1px dashed rgb(217, 217, 217);*/
border: none;
}
.avatar-delete {
font-size: 20px;
color: red;
}
</style>
@@ -0,0 +1,142 @@
<template>
<div>
<el-dialog :visible.sync="sendDialogVisible" title="发送通知" width="45%" :close-on-click-modal="false" @closed="sendDialogClose">
<el-form ref="sendForm" :model="formData" label-width="80px">
<el-form-item label="发送对象" prop="activityGroupId" :rules="[{required: true, message: '请选择发送对象', trigger: ['blur', 'change']}]">
<el-select @change="groupChange" :disabled="group_id" placeholder="请选择活动组别" clearable style="width: 100%" v-model="formData.activityGroupId">
<el-option :label="item.groupName"
:value="item.groupId"
v-for="item in activityGroupList"></el-option>
</el-select>
</el-form-item>
<el-form-item label="发送方式" prop="sendTypes" :rules="[{required: true, message: '请选择发送方式', trigger: ['blur', 'change']}]">
<el-checkbox-group v-model="formData.sendTypes" size="medium">
<el-checkbox border label="1">短信发送</el-checkbox>
<el-checkbox border label="4">微信发送</el-checkbox>
</el-checkbox-group>
</el-form-item>
<el-form-item label="发送内容" prop="content" :rules="[{required: true, message: '请选择发送内容', trigger: ['blur', 'change']}]">
<el-input
v-model="formData.content"
:rows="6"
placeholder="请输入内容"
type="textarea">
</el-input>
</el-form-item>
</el-form>
<span slot="footer" class="dialog-footer">
<el-button @click="sendDialogVisible = false"> </el-button>
<el-button :disabled="!this.formData.activityGroupId" type="primary" @click="doSend()"> </el-button>
</span>
</el-dialog>
</div>
</template>
<script>
module.exports = {
props: {
group_id: {
type: String, default: ''
},
},
model: {
},
data() {
return {
sendDialogVisible: false,
activityGroupList: [],
formData: {
sendTypes: [],
activityGroupId: '',
content: '',
},
}
},
watch: {
},
methods: {
sendDialogClose() {
if(this.$refs['sendForm']) {
this.$refs['sendForm'].resetFields()
}
},
openDialog(groupId) {
if(!groupId) {
this.$notify.warning({title: '警告', message: '您选择的活动没有发送对象!'})
return
}
this.group_id = groupId
if(groupId) {
this.formData.activityGroupId = Number(groupId)
}
this.sendDialogVisible = true
},
groupChange(val) {
},
async doSend() {
const valid = await this.$refs['sendForm'].validate()
if (!valid) return
const group = this.activityGroupList.find(o => o.groupId === this.formData.activityGroupId)
const groupName = group !== undefined ? group.groupName : ''
const confirm = await this.$confirm('您确定要给【' + groupName + '】发送通知吗?', '提示', {
confirmButtonText: '确定',
cancelButtonText: '取消',
type: 'warning'
})
if (confirm) {
const loading = this.$loading({
lock: true,
text: '正在发送...',
spinner: 'el-icon-loading',
background: COVER_LAYER_COLOR
});
this.formData.activityGroupId = this.group_id
this.formData.flag = this.group_id
const resp = await $.post('/platform/msgNotify/send/sendMsgByGroupId', {
msgNotify: JSON.stringify(this.formData),
})
if (resp.code === 0) {
this.$notify.success({title: '成功', message: resp.msg})
this.sendDialogVisible = false
} else {
this.$notify.warning({title: '警告', message: resp.msg})
}
loading.close()
}
},
async getActivityGroup() {
const resp = await $.get('/platform/activity/basic/scope/getActivityUserScopeGroup')
this.activityGroupList = resp.data
},
async initData() {
await this.getActivityGroup()
},
},
computed: {
},
created() {
this.initData()
}
}
</script>
<style scoped>
</style>
@@ -0,0 +1,144 @@
<template>
<div>
<wp-upload :key="key" :url="uploadUrl"
:file-list="hxfileList"
:max-file-number="maxnum"
:allow-files="allowfiles"
:upload-auto="true"
upload-file-param="file"
@on-delete="onDelete"
@docexcel-preview="docexcelPreview"
@on-upload-after="uploadAfter">
</wp-upload>
</div>
</template>
<script>
const METHOD_NAME = "change"
module.exports = {
props: {
filex: {
type: String
},
resfile: {
type: 'Object',
default: () => {
}
},
allowfiles: {
type: 'Array',
default: () => []
},
maxnum: {
type: [String, Number]
}
},
watch: {
filex: {
handler(val) {
if (val) {
this.hxfileList.push({url: val})
}
},
immediate: true
},
resfile(val) {
this.hxfileList = [{url: FILE_DOMAIN + val}]
this.key = Math.random()
},
},
data() {
return {
key: Math.random(),
uploadUrl: '/platform/Common/uploadFile',
fileList: [],
filePath: '',
hxfileList: []
}
},
methods: {
uploadAfter({data, fileId}) {
if (data && data.code === 0) {
//fileId 文件的唯一ID 组件生成
this.resfile = {...data.data, fileId}
this.$emit('update:resfile', this.resfile.filepath)
}
},
onDelete(file) {
if (file.status === 2) {
for (let index in this.resfile) {
if (this.resfile[index].fileId === file.id) {
$.post('/platform/Common/deleteFile', {filepath: this.resfile[index].filepath})
this.resfile.splice(index, 1)
}
}
}
},
docexcelPreview(id) {
//61行的fileId
for (let index in this.resfile) {
if (this.resfile[index].fileId === id) {
window.open('/platform/base/Common/preview?filepath=' + this.resfile[index].filepath + '&fileid=' + this.resfile[index].id)
}
}
},
handleChange(file, fileList) {
const delFile = () => {
for (let i = 0; i < fileList.length; i++) {
for (let i = 0; i < fileList.length; i++) {
if (file === fileList[i]) {
fileList.splice(i, 1);
}
}
}
if (this.size === 0) {
this.$message.warning("您选择的是空文件!");
delFile()
}
if (!uploadFileType.includes(file.name.split('.')[1])) {
this.$message.warning("文件格式不支持!");
delFile()
}
let formData = new FormData()
formData.append("file", file.raw, file.raw.name);
$.ajax({
url: "/platform/Common/uploadFile",
type: "post",
data: formData,
processData: false,
contentType: false,
success: (res) => {
const {code, data, msg} = res
if (code == 0) {
file.v = data
//this.$emit(METHOD_NAME, data)
this.$emit('update:' + METHOD_NAME, data)
}
},
error: res => {
const {code, data, msg} = res
this.$message.error(msg);
}
});
}
},
handleRemove(file, fileList) {
if (file.v) {
$.post('/platform/Common/deleteFile', {filepath: file.v.filepath})
for (let index in this.resfile) {
if (this.resfile[index].filepath === file.v.filepath) {
this.resfile.splice(index, 1)
}
}
}
},
}
}
</script>
<style>
</style>
@@ -0,0 +1,671 @@
<template>
<div>
<el-upload :key="key"
:action="FILE_UPLOAD_ADDRESS"
limit="1" :before-upload="beforeUpload"
list-type="picture-card" :file-list="fileList" :on-success="onSuccess">
<i slot="default" class="el-icon-plus"></i>
<div slot="file" slot-scope="{file}">
<template v-if="resolvingShowByFileName(file.data.filepath) == 1">
<el-image
style="width: 100px; height: 100px"
:src="getFileItemShowIcon(file.data.filepath)"
fit="cover"></el-image>
<!-- <img class="show-img" :src="getFileItemShowIcon(file.filepath)" :alt="file.filename"/>-->
</template>
<template v-else>
<svg aria-hidden="true" style="width: 100px; height: 100px">
<use :xlink:href="getFileItemShowIcon(file.data.filepath)"></use>
</svg>
</template>
<span class="el-upload-list__item-actions">
<span
class="el-upload-list__item-preview"
@click="showSource(file.data)"
>
<i class="el-icon-zoom-in"></i>
</span>
<span
class="el-upload-list__item-delete"
@click="handleDownload(file)"
>
<i class="el-icon-download"></i>
</span>
<span
class="el-upload-list__item-delete"
@click="handleRemove(file)"
>
<i class="el-icon-delete"></i>
</span>
</span>
</div>
</el-upload>
</div>
</template>
<script>
/**
* 文件类型解析
* @type {{isImg: wpUploadFileTypeResolve.isImg}}
*/
let fileTypeResolving = {
/**
* 是否是一张图片
*/
isImg: function (fileItem) {
return fileTypeResolving.resolvingByType(fileItem.type, /image\/(\w)*/)
},
/**
* 通过后缀验证图片
*/
isImgByName: function (fileItemName) {
let checkSuffixArray = ['jpg', 'png', 'jpeg', 'bmp', 'gif', 'webp', 'tif', 'svg', 'wmf'];
return fileTypeResolving.resolvingByName(fileItemName, checkSuffixArray)
},
/**
* 是否是视频
*/
isVideo: function (fileItem) {
return fileTypeResolving.resolvingByType(fileItem.type, /video\/(\w)*/)
},
/**
* 通过后缀验证图片
*/
isVideoByName: function (fileItemName) {
let checkSuffixArray = ['mp4', 'Ogg', 'webm'];
return fileTypeResolving.resolvingByName(fileItemName, checkSuffixArray)
},
/**
* 是否是音频
*/
isAudio: function (fileItem) {
return fileTypeResolving.resolvingByType(fileItem.type, /audio\/(\w)*/)
},
/**
* 通过后缀验证图片
*/
isAudioByName: function (fileItemName) {
let checkSuffixArray = ['mp3', 'ogg', 'wav'];
return fileTypeResolving.resolvingByName(fileItemName, checkSuffixArray)
},
/**
* 是否是doc文件
*/
isDoc: function (fileItemName) {
let checkSuffixArray = ['doc', 'docx', 'dot', 'dotx'];
return fileTypeResolving.resolvingByName(fileItemName, checkSuffixArray);
},
/**
* 是否是excel文件
*/
isExcel: function (fileItemName) {
let checkSuffixArray = ['xls', 'xlsx', 'csv', 'xlt', 'xltx'];
return fileTypeResolving.resolvingByName(fileItemName, checkSuffixArray);
},
/**
* 是否是PPT文件
*/
isPPT: function (fileItemName) {
let checkSuffixArray = ['ppt', 'pptx', 'pot', 'potx', 'odp'];
return fileTypeResolving.resolvingByName(fileItemName, checkSuffixArray);
},
/**
* 是否是Pdf文件
*/
isPdf: function (fileItemName) {
let checkSuffixArray = ['pdf'];
return fileTypeResolving.resolvingByName(fileItemName, checkSuffixArray);
},
/**
* 是否是压缩文件
* @param fileItem
* @returns {boolean}
*/
isZip: function (fileItemName) {
let checkSuffixArray = ['zip', '7z', 'war', 'tar', 'rar', 'jar', 'zipx', 'zix', 'zoo'];
return fileTypeResolving.resolvingByName(fileItemName, checkSuffixArray);
},
isWeb: function (fileItemName) {
let checkSuffixArray = ['html', 'htm'];
return fileTypeResolving.resolvingByName(fileItemName, checkSuffixArray);
},
isTxt: function (fileItemName) {
let checkSuffixArray = ['txt'];
return fileTypeResolving.resolvingByName(fileItemName, checkSuffixArray);
},
isPsd: function (fileItemName) {
let checkSuffixArray = ['psd'];
return fileTypeResolving.resolvingByName(fileItemName, checkSuffixArray);
},
isCad: function (fileItemName) {
let checkSuffixArray = ['cad'];
return fileTypeResolving.resolvingByName(fileItemName, checkSuffixArray);
},
isIso: function (fileItemName) {
let checkSuffixArray = ['iso'];
return fileTypeResolving.resolvingByName(fileItemName, checkSuffixArray);
},
isExe: function (fileItemName) {
let checkSuffixArray = ['exe'];
return fileTypeResolving.resolvingByName(fileItemName, checkSuffixArray);
},
/**
* 根据文件类型来解析
* @param fileType 文件类型
* @param checkTypeModel 文件类型模型,如:image\/(\w)*
* @returns {boolean}
*/
resolvingByType: function (fileType, checkTypeModel) {
if (checkTypeModel.test(fileType)) {
return true;
}
return false;
},
/**
* 根据名字和名字后缀名来验证文件
* @param fileName 文件名
* @param checkSuffixArray 文件类型包含的后缀
*/
resolvingByName: function (fileName, checkSuffixArray) {
let suffixName = wpUploadFileTools.getSuffixNameByFileName(fileName);
// 名字是否有效
if (!wpUploadDataValid.isValidStr(suffixName)) {
// 无效直接返回false
return false;
}
suffixName = suffixName.trim();
suffixName = suffixName.toLowerCase();
if (checkSuffixArray.indexOf(suffixName) != -1) {
return true;
}
return false;
}
}
/**
* 文件工具
* @type {{}}
*/
let wpUploadFileTools = {
/**
* 获取文件显示模版
* @param fileItem
*/
wapFileItemShow: function (fileItem) {
return wpUploadFileTools.wapFileItemShowBase(fileItem, false);
},
/**
* 包装已上传的文件列表
*/
wapFileItemShowWithUpload(uploadFile) {
return wpUploadFileTools.wapFileItemShowBase(uploadFile, true);
},
/**
* 获取文件显示的基本操作
*/
wapFileItemShowBase(fileItem, isUploaded = false) {
let fileName = "";
let suffix = "";
let show = "";
let showIcon = "";
if (!isUploaded) {
fileName = fileItem.name;
suffix = wpUploadFileTools.getSuffixNameByFileName(fileName);
show = wpUploadFileTools.resolvingShow(fileItem);
showIcon = wpUploadFileShowResolving.getFileItemShowIcon(show, fileItem, false);
} else {
fileName = fileItem.name ? fileItem.name : wpUploadFileTools.resolvingUrlFileName(fileItem.url);
let fileNameGetOFuRL = wpUploadFileTools.resolvingUrlFileName(fileItem.url);
suffix = wpUploadFileTools.getSuffixNameByFileName(fileNameGetOFuRL);
show = wpUploadFileTools.resolvingShowByFileName(fileNameGetOFuRL);
showIcon = wpUploadFileShowResolving.getFileItemShowIcon(show, fileItem.url, true);
}
let fileItemShow = {
// 文件的id
id: wpUploadFileTools.uuid(),
// 文件对象
file: null,
// 文件的类型
type: null,
// 文件的大小
size: null,
// 文件的名字
name: fileName,
// 文件地址
url: null,
// 后缀
suffix: suffix,
// 显示的类型
show: show,
// 显示的图标或者图片地址
showIcon: showIcon,
// 显示进度条
processStatus: {
show: false,
width: 0,
isFail: false
},
// 文件来源,0选择文件上传,1回显文件
fileSource: 0,
// 状态0未上传,失败也会转到0,1正在上传,2已经上传
status: 0,
// 上传文件的描述
fileDes: null
}
if (!isUploaded) {
// 如果非选择文件下面三个属性为null
fileItemShow.file = fileItem;
fileItemShow.type = fileItem.type;
fileItemShow.size = fileItem.size;
} else {
// 文件描述
fileItemShow.status = 2;
fileItemShow.fileDes = fileItem;
fileItemShow.fileSource = 1;
fileItemShow.url = fileItem.url;
}
return fileItemShow;
},
/**
* 解析URL的文件名字
*/
resolvingUrlFileName: function (fileUrl) {
let index = fileUrl.lastIndexOf("/");
if (index <= 0) {
index = fileUrl.lastIndexOf("\\");
}
index = index + 1;
let fileName = fileUrl.substring(index, fileUrl.length);
return fileName;
},
/**
* 获取文件名后缀
* @param fileName 文件名全名
* */
getSuffixNameByFileName: function (fileName) {
let str = fileName;
let index = str.lastIndexOf(".");
if (index < 0) {
return "";
}
let pos = index + 1;
return str.substring(pos, str.length);
},
/**
* 解析显示类型
* @param fileItem 文件
* @returns {number}
*/
resolvingShow: function (fileItem) {
// 默认0普通文件
let showResult = 0;
if (wpUploadFileTypeResolving.isImg(fileItem)) {
showResult = 1;
} else if (wpUploadFileTypeResolving.isVideo(fileItem)) {
showResult = 2;
} else if (wpUploadFileTypeResolving.isAudio(fileItem)) {
showResult = 3;
} else if (wpUploadFileTypeResolving.isDoc(fileItem.name)) {
showResult = 4;
} else if (wpUploadFileTypeResolving.isExcel(fileItem.name)) {
showResult = 5;
} else if (wpUploadFileTypeResolving.isPPT(fileItem.name)) {
showResult = 6;
} else if (wpUploadFileTypeResolving.isPdf(fileItem.name)) {
showResult = 7;
} else if (wpUploadFileTypeResolving.isZip(fileItem.name)) {
showResult = 8;
} else if (wpUploadFileTypeResolving.isWeb(fileItem.name)) {
showResult = 9;
} else if (wpUploadFileTypeResolving.isTxt(fileItem.name)) {
showResult = 10;
} else if (wpUploadFileTypeResolving.isPsd(fileItem.name)) {
showResult = 11;
} else if (wpUploadFileTypeResolving.isCad(fileItem.name)) {
showResult = 12;
} else if (wpUploadFileTypeResolving.isIso(fileItem.name)) {
showResult = 13;
} else if (wpUploadFileTypeResolving.isExe(fileItem.name)) {
showResult = 14;
}
return showResult
},
/**
* 解析显示类型
* @param fileItem 文件
* @returns {number}
*/
resolvingShowByFileName: function (fileItemName) {
// 默认0普通文件
let showResult = 0;
if (wpUploadFileTypeResolving.isImgByName(fileItemName)) {
showResult = 1;
} else if (wpUploadFileTypeResolving.isVideoByName(fileItemName)) {
showResult = 2;
} else if (wpUploadFileTypeResolving.isAudioByName(fileItemName)) {
showResult = 3;
} else if (wpUploadFileTypeResolving.isDoc(fileItemName)) {
showResult = 4;
} else if (wpUploadFileTypeResolving.isExcel(fileItemName)) {
showResult = 5;
} else if (wpUploadFileTypeResolving.isPPT(fileItemName)) {
showResult = 6;
} else if (wpUploadFileTypeResolving.isPdf(fileItemName)) {
showResult = 7;
} else if (wpUploadFileTypeResolving.isZip(fileItemName)) {
showResult = 8;
} else if (wpUploadFileTypeResolving.isWeb(fileItemName)) {
showResult = 9;
} else if (wpUploadFileTypeResolving.isTxt(fileItemName)) {
showResult = 10;
} else if (wpUploadFileTypeResolving.isPsd(fileItemName)) {
showResult = 11;
} else if (wpUploadFileTypeResolving.isCad(fileItemName)) {
showResult = 12;
} else if (wpUploadFileTypeResolving.isIso(fileItemName)) {
showResult = 13;
} else if (wpUploadFileTypeResolving.isExe(fileItemName)) {
showResult = 14;
}
return showResult
},
/**
* 生成UUID
* @returns {string}
*/
uuid: function () {
let str = wpUploadFileTools.uuidFull();
str = str.replace(/-/g, "");
return str;
},
uuidFull() {
let s = []
let hexDigits = "0123456789abcdef"
for (var i = 0; i < 36; i++) {
s[i] = hexDigits.substr(Math.floor(Math.random() * 0x10), 1)
}
s[14] = "4"
s[19] = hexDigits.substr((s[19] & 0x3) | 0x8, 1)
s[8] = s[13] = s[18] = s[23] = "-"
let uuid = s.join("")
return uuid
},
/**
* 禁止某个dom的某个事件
*/
disableObjEvent(domObj, eventName) {
domObj.addEventListener(eventName, function (e) {
e.preventDefault();
})
}
}
/**
* 数据验证工具
* @type {{isValid: wpUploadDataValid.isValid}}
*/
let wpUploadDataValid = {
isValid: function (obj) {
if (undefined === obj || null === obj) {
return false;
}
return true;
},
isValidStr: function (str) {
let isValidObj = wpUploadDataValid.isValid(str);
if (!isValidObj) {
return isValidObj;
}
str = str.trim();
if ("" == str || '' == str) {
return false;
}
return true;
},
isValidArray(array) {
if (null == array || array == undefined || array.length <= 0) {
return false;
}
return true;
}
}
module.exports = {
props: {
files: Array,
type: {
type: Array,
default: ['jpg', 'png', 'doc', 'docx', 'xls', 'xlsx', 'pdf']
},
max_size: {
type: Number,
default: 5 * 1024 * 1024
},
view: {
type: Boolean,
default: false
}
},
watch: {
files(val) {
this.updateFileList(val)
this.key = Math.random()
}
},
data() {
return {
key: Math.random(),
dialogImageUrl: '',
dialogVisible: false,
fileList: []
}
},
methods: {
/**
* 查看资源
*/
showSource(showItem) {
const show = this.resolvingShowByFileName(showItem.filepath)
if (show == 1 || show == 2 || show == 3) {
dd3s.showpic(showItem.filepath)
} else if (show == 4 || show == 5) {
dd3s.preview(showItem.filepath, showItem.id)
}
},
/**
* 解析显示类型
* @param fileItem 文件
* @returns {number}
*/
resolvingShowByFileName(fileItemName) {
// 默认0普通文件
let showResult = 0;
if (fileTypeResolving.isImgByName(fileItemName)) {
showResult = 1;
} else if (fileTypeResolving.isVideoByName(fileItemName)) {
showResult = 2;
} else if (fileTypeResolving.isAudioByName(fileItemName)) {
showResult = 3;
} else if (fileTypeResolving.isDoc(fileItemName)) {
showResult = 4;
} else if (fileTypeResolving.isExcel(fileItemName)) {
showResult = 5;
} else if (fileTypeResolving.isPPT(fileItemName)) {
showResult = 6;
} else if (fileTypeResolving.isPdf(fileItemName)) {
showResult = 7;
} else if (fileTypeResolving.isZip(fileItemName)) {
showResult = 8;
} else if (fileTypeResolving.isWeb(fileItemName)) {
showResult = 9;
} else if (fileTypeResolving.isTxt(fileItemName)) {
showResult = 10;
} else if (fileTypeResolving.isPsd(fileItemName)) {
showResult = 11;
} else if (fileTypeResolving.isCad(fileItemName)) {
showResult = 12;
} else if (fileTypeResolving.isIso(fileItemName)) {
showResult = 13;
} else if (fileTypeResolving.isExe(fileItemName)) {
showResult = 14;
}
return showResult
},
/**
* 获取文件显示图标
* @param filePath
* @returns {string}
*/
getFileItemShowIcon(filePath) {
let showIcon = '';
switch (this.resolvingShowByFileName(filePath)) {
case 0:
showIcon = "#icon-yunpanlogo-3";
break;
// 图片
case 1:
showIcon = this.getImgShowIcon(filePath);
break;
// 视频
case 2:
showIcon = "#icon-yunpanlogo-6";
break;
// 音乐
case 3:
showIcon = "#icon-yunpanlogo-4";
break;
// doc
case 4:
showIcon = "#icon-yunpanlogo-2";
break;
// excel
case 5:
showIcon = "#icon-yunpanlogo-";
break;
// ppt
case 6:
showIcon = "#icon-yunpanlogo-1";
break;
// pdf
case 7:
showIcon = "#icon-yunpanlogo-12";
break;
// zip
case 8:
showIcon = "#icon-yasuobao";
break;
// web文件
case 9:
showIcon = "#icon-yunpanlogo-5";
break;
// txt文件
case 10:
showIcon = "#icon-yunpanlogo-7";
break;
// PSD
case 11:
showIcon = "#icon-yunpanlogo-10";
break;
// cad
case 12:
showIcon = "#icon-yunpanlogo-11";
break;
// ISO
case 13:
showIcon = "#icon-yunpanlogo-8";
break;
// 可执行
case 14:
showIcon = "#icon-yunpanlogo-9";
break;
// 普通文件
default:
showIcon = "#icon-yunpanlogo-3";
}
return showIcon;
},
/**
* 获取图片的显示图标
* @param fileItem
* @returns {string|*}
*/
getImgShowIcon(fileItem) {
return FILE_DOMAIN + fileItem;
},
updateFileList(val) {
if (!val || !val.length) {
this.fileList = []
return
}
this.fileList = val.map(v => {
return {data: v, uid: v.id, name: v.filename, url: FILE_DOMAIN + v.filepath, status: 'success'}
})
},
change() {
this.$emit("update:files", this.fileList.map(v => v.data))
},
onSuccess(response, file, fileList) {
const {data} = response
file.data = data
this.fileList = fileList
this.change()
},
beforeUpload(file) {
const type = this.type.includes(file.name.split('.')[1].toLowerCase());
const size = file.size < this.max_size;
if (!type) {
this.$message.warning(`上传文件只能是 ${this.type.map(v => v.toUpperCase()).join("/")} 格式!`);
}
if (!size) {
this.$message.warning(`上传文件大小不能超过 ${this.max_size / 1024 / 1024} MB!`);
}
return type && size;
},
handleRemove(file) {
if (file.data) {
const {filename, filepath} = file.data
$.post(FILE_DELETE_ADDRESS, {filepath})
this.fileList.splice(this.fileList.findIndex(v => v == file), 1)
this.change()
}
},
handleDownload(file) {
const {filepath, filename} = file.data
if (filepath && filename) {
dd3s.download(filepath, filename)
}
}
},
created() {
this.updateFileList(this.files)
}
}
</script>
<style>
.el-upload--picture-card, .el-upload-list--picture-card .el-upload-list__item {
width: 100px;
height: 100px;
}
.el-upload--picture-card {
line-height: 110px;
}
.el-upload-list--picture-card .el-upload-list__item-actions span + span {
margin-left: 5px;
}
.el-upload-list--picture-card .el-upload-list__item-actions {
font-size: 16px;
}
</style>
@@ -0,0 +1,120 @@
<template>
<div class="v-tree-layout">
<div class="shrink" :style="'left:'+(showTree?'calc(20% - 15px)':'0')" @click="shrink">
<i v-if="!showTree" class="el-icon-arrow-right"></i>
<i v-else class="el-icon-arrow-left"></i>
</div>
<div class="v-tree-layout-left">
<slot name="tree"></slot>
</div>
<div class="v-tree-layout-right">
<slot></slot>
</div>
</div>
</template>
<script>
module.exports = {
props: {},
data() {
return {
showTree: true,
}
},
methods: {
shrink() {
if (this.showTree) {
$(".v-tree-layout-left").width(0)
$(".v-tree-layout-right").width('100%')
this.showTree = false
} else {
$(".v-tree-layout-left").width('20%')
$(".v-tree-layout-right").width('80%')
this.showTree = true
}
},
},
}
</script>
<style>
.shrink {
position: absolute;
height: 30px;
width: 30px;
display: flex;
justify-content: center;
align-items: center;
border-radius: 15px;
background-color: white;
z-index: 99;
top: 0;
bottom: 0;
margin: auto;
box-shadow: 0 0 5px rgb(200, 200, 200);
cursor: pointer;
transition: all 500ms;
}
.shrink:hover {
box-shadow: 0 0 10px rgb(150, 150, 150);
}
.v-tree-layout-left::-webkit-scrollbar { /*滚动条整体样式*/
width: 4px; /*高宽分别对应横竖滚动条的尺寸*/
height: 10px;
}
.v-tree-layout-left::-webkit-scrollbar-thumb { /*滚动条里面小方块*/
border-radius: 10px;
background: #dcdcdc;
}
.v-tree-layout-left::-webkit-scrollbar-track { /*滚动条里面轨道*/
-webkit-box-shadow: inset 0 0 5px transparent;
border-radius: 10px;
background: transparent;
}
.v-tree-layout {
width: 100%;
height: 100%;
position: relative;
display: flex;
flex-direction: row;
}
.v-tree-layout-left {
width: 20%;
}
.v-tree-layout-left, .v-tree-layout-left .el-tree {
background-color: #FFFFFF;
}
.v-tree-layout-right {
width: 80%;
border-left: 1px solid rgb(240, 240, 240);
}
.v-tree-layout-left, .v-tree-layout-right {
height: 100%;
box-sizing: border-box;
overflow: auto;
transition: all 500ms;
position: relative;
}
</style>
@@ -0,0 +1,95 @@
/**
*Desc:
*Create by: jug
*Create time:2023/6/8/10:29
*/
<template>
<div style="margin: 10px 0">
<!-- <vi-title style="display:flex;align-items: center;margin:10px 0" title="过滤条件匹配:"></vi-title>-->
<enum-select v-model="matchMethod" :clearable="false" enum="MatchMethod" label="description"
style="width: 300px"
value="name"></enum-select>
<div v-for="(r,index) in rules" :key="r.name +index" style="margin: 5px 0">
<div style="display: flex;column-gap: 10px">
<el-select v-model="r.name" clearable filterable placeholder="请选择字段">
<el-option
v-for="column in columnInfos"
:key="column.COLUMN_NAME"
:label="column.COLUMN_COMMENT"
:value="column.COLUMN_NAME">
</el-option>
</el-select>
<el-select v-model="r.cnd" clearable filterable placeholder="请选择条件">
<el-option
v-for="column in cnds"
:key="column.value"
:label="column.description"
:value="column.value">
</el-option>
</el-select>
<div style="width: 300px">
<el-input v-model="r.value" placeholder="请输入值"></el-input>
</div>
<div class="start" style="display: flex;align-items: center;column-gap: 10px;">
<el-button type="danger" @click="rules.splice(index,1)">-</el-button>
</div>
</div>
</div>
<el-button size="small" type="primary" @click="rules.push({})">添加条件</el-button>
</div>
</template>
<script>
module.exports = {
name: "UserCnd",
props: {},
components: {'enum-select': httpVueLoader('/components/plugins/EnumSelect.vue?v=1.0.0'),},
data() {
return {
columnInfos: [],
rules: [
{}
],
cnds: [
{value: "=", desc: "等于"},
{value: "!=", desc: "不等于"},
],
matchMethods: [],
matchMethod: "AND"
}
},
watch: {
matchMethod(val) {
this.$emit('cnd', {matchMethod: val, rules: this.rules})
},
rules(val) {
this.$emit('cnd', {matchMethod: this.matchMethod, rules: val})
}
},
methods: {
async getColumnInfo() {
const {data, msg, code} = await $.post('/platform/activity/basic/scope/getUserTableColumnInfo')
if (code !== 0) {
this.$notify.warning(msg)
return
}
this.columnInfos = data
}
},
created() {
this.getColumnInfo()
getEnumOptions('MatchMethod').then(res => this.matchMethods = res)
getEnumOptions('ConditionalOperational').then(res => this.cnds = res)
}
}
</script>
<style scoped>
</style>
@@ -0,0 +1,496 @@
<template>
<div>
<el-card shadow="never">
<div class="search">
<div class="search-item">
<div class="search-item-label">活动分组</div>
<div class="search-item-option">
<el-select placeholder="活动分组" v-model="pageForm.groupId"
style="width: 100%;"
@change="doSearch();viewGroupName()"
filterable>
<el-option v-for="item in activityGroupList" :label="item.groupName"
:value="item.groupId"></el-option>
</el-select>
</div>
</div>
<div class="search-item">
<div class="search-item-label">姓名工号</div>
<div class="search-item-option">
<el-input placeholder="请输入内容" clearable v-model="pageForm.searchKeyword"
style="width: 100%"
@keyup.enter.native="doSearch">
<el-select v-model="pageForm.searchName" slot="prepend"
placeholder="查询类型"
style="width: 80px;">
<el-option label="姓名" value="username"></el-option>
<el-option label="工号" value="loginname"></el-option>
</el-select>
</el-input>
</div>
</div>
<div class="search-item"
v-if="is_sysadmin||is_A06||is_H03">
<div class="search-item-label">所属工会</div>
<div class="search-item-option">
<el-select placeholder="所属工会" v-model="pageForm.unionId"
style="width: 100%;"
clearable="true"
@change="flushUnits" @clear="flushUnits"
filterable="true">
<el-option v-for="item in unions" :label="item.unionname"
:value="item.id"></el-option>
</el-select>
</div>
</div>
<div class="search-item">
<div class="search-item-label">所属单位</div>
<div class="search-item-option">
<el-select placeholder="所属单位" v-model="pageForm.unitId" style="width: 100%;"
clearable="true"
@change="doSearch"
filterable="true">
<el-option v-for="item in units" :label="item.name"
:value="item.id"></el-option>
</el-select>
</div>
</div>
<!--<div class="search-item"
v-if="${@shiro.hasRole('sysadmin')}">
<div class="search-item-label">活动工会</div>
<div class="search-item-option">
<el-select placeholder="所属工会" v-model="pageForm.activityUnionId"
style="width: 100%;"
clearable="true"
@change="flushUnits" @clear="flushUnits"
filterable="true">
<el-option v-for="item in ActivityUnions" :label="item.unionname"
:value="item.id"></el-option>
</el-select>
</div>
</div>
<div class="search-item" v-if="${@shiro.hasRole('sysadmin')}">
<div class="search-item-label">活动单位</div>
<div class="search-item-option">
<el-select placeholder="所属单位" v-model="pageForm.activityUnitId"
style="width: 100%;"
clearable="true"
@change="doSearch"
filterable="true">
<el-option v-for="item in ActivityUnits" :label="item.name"
:value="item.id"></el-option>
</el-select>
</div>
</div>-->
<div class="search-item">
<div class="search-item-label">人员类型</div>
<div class="search-item-option">
<dict-select v-model="pageForm.personType" style="width: 100%" clearable
placeholder="人员类型"
@change="doSearch"
code="UserType"></dict-select>
</div>
</div>
<div class="search-item">
<div class="search-item-label">在职状态</div>
<div class="search-item-option">
<dict-select v-model="pageForm.userState" style="width: 100%" clearable
placeholder="在职状态"
@change="doSearch"
code="UserState"></dict-select>
</div>
</div>
<div class="search-query">
<el-button type="primary" icon="el-icon-search" @click="doSearch">搜索</el-button>
</div>
</div>
</el-card>
<el-card shadow="never" class="mt10">
<table-tool :label="currentGroupName" :app="this">
<template #label_end>
<!-- <span class="text-danger pl5">提醒删除活动分组操作请先选择某个活动分组后再点击右边的删除按钮</span>-->
</template>
<template #func>
<el-button v-if="is_sysadmin||is_A06"
type="primary" size="medium" icon="el-icon-printer" @click="dialogVisible = true">
导入XLSX查询
</el-button>
<el-button @click="doExportUser" icon="el-icon-printer"
size="medium" type="primary" :disabled="!pageForm.groupId">
导出活动分组人员xlsx
</el-button>
<el-button @click="doDelete(null,pageForm.groupId)"
type="danger"
size="medium" :disabled="tableData.length===0">
删除{{ currentGroupName }}
</el-button>
</template>
</table-tool>
<el-table ref="userTable" :data="tableData" stripe border :size="tableSize" @sort-change="pageOrder">
<el-table-column type="index" label="序号" width="80px"></el-table-column>
<el-table-column
align="center"
header-align="center"
v-for="column in tableColumns"
show-overflow-tooltip
:label="column.label"
:prop="column.prop"
:sortable="column.sortable"
></el-table-column>
<el-table-column align="center" header-align="center" label="操作" width="100">
<template scope="{row}">
<el-button size="mini" type="danger" @click="doDelete(row.id,null)">删除
</el-button>
</template>
</el-table-column>
</el-table>
<el-row class="el-pagination-container" style="margin-bottom: 0px">
<el-pagination
@size-change="pageSizeChange"
@current-change="pageNumberChange"
:current-page="pageForm.pageNumber"
:page-sizes="[5,10, 20, 30, 50]"
:page-size="pageForm.pageSize"
layout="total, sizes, prev, pager, next"
:total="pageForm.totalCount">
</el-pagination>
</el-row>
</el-card>
<el-dialog title="人员导入" :visible.sync="dialogVisible" width="50%" :close-on-click-modal="false" append-to-body>
<el-timeline>
<el-timeline-item timestamp="下载模板" placement="top">
<el-card>
<el-button size="medium" type=""
@click="window.open('/platform/activity/basic/user/downloadImport')"
icon="el-icon-download">下载模板
</el-button>
</el-card>
</el-timeline-item>
<el-timeline-item timestamp="上传文件" placement="top">
<el-card>
<el-upload
name="file"
ref="upload"
:on-remove="(file, fileList) => {
importData.fileList = fileHandleRemove(file, fileList)
}"
:on-change="(file, fileList) => {
importData.fileList = fileHandleChange(file, fileList,{type:['xls','xlsx']})
}"
:auto-upload="false"
:limit="1"
:file-list="importData.fileList">
<el-button size="medium" type="" icon="el-icon-upload"
style="width: 200px">选择文件
</el-button>
<div class="el-upload__tip" slot="tip" style="color: #F56C6C">
只能上传 xls/xlsx 文件
</div>
</el-upload>
</el-card>
</el-timeline-item>
<el-timeline-item placement="top" timestamp="导入结果">
<el-card shadow="never">
<p>总记录数:{{ errorInfoData.totalCount }}</p>
<p>成功数:<span class="text-success">{{ errorInfoData.successCount }}</span></p>
<p>错误数:<span class="text-danger">{{ errorInfoData.errorCount }}</span></p>
<el-link @click="exportErrors" type="primary" v-if="errorInfoData.errorCount>0">下载错误记录
</el-link>
</el-card>
</el-timeline-item>
</el-timeline>
<span slot="footer" class="dialog-footer">
<el-button @click="dialogVisible = false" type="primary"
:disabled="importLoading">取 消</el-button>
<el-button type="primary" @click="clearSearchCnd"
:loading="importLoading">清空查询条件</el-button>
<el-button type="primary" @click="doImport" :loading="importLoading">核对人员</el-button>
<el-button type="primary" @click="doImportSearch"
:loading="importLoading">查询人员</el-button>
</span>
</el-dialog>
</div>
</template>
<script>
module.exports = {
props: {
group_id: {
type: String, default: ''
}
},
computed: {
is_H10() {
return this.roleData.is_H10
},
is_A06() {
return this.roleData.is_A06
},
is_H04() {
return this.roleData.is_H04
},
is_H02() {
return this.roleData.is_H02
},
is_H03() {
return this.roleData.is_H03
},
is_sysadmin() {
return this.roleData.is_sysadmin
},
unionid() {
return this.roleData.unionid
},
},
data() {
return {
activityGroupList: [],
ActivityUnions: [],
ActivityUnits: [],
unions: [],
units: [],
pageForm: {
unionId: "",
unitId: "",
searchName: "username",
personTypes: [],
userStates: [],
memberStatus: [],
year: moment().format('YYYY')
},
tableColumns: [
{prop: 'loginName', label: '工号'},
{prop: 'userName', label: '姓名'},
{prop: 'sex', label: '性别', sortable: true},
{prop: 'birthday', label: '出生年月'},
{prop: 'mobile', label: '联系电话'},
{prop: 'personType', label: '人员类型', sortable: true},
{prop: 'userState', label: '在职状态', sortable: true},
{prop: 'unitName', label: '所属单位', sortable: true},
{prop: 'unionName', label: '所属工会', sortable: true},
{prop: 'activityUnionName', label: '活动工会', sortable: true},
{prop: 'groupName', label: '所属分组', sortable: true},
],
roleData: {},
currentGroupName: null,
errorInfoData: {
totalCount: 0,
successCount: 0,
errorCount: 0,
errorList: 0,
},
dialogVisible: false,
importLoading: false,
importData: {
fileList: [],
},
successUserIdList: []
}
},
mixins: [initTableMixins],
components: {
'dict-select': httpVueLoader('/components/plugins/DictSelect.vue?v=1.0.0'),
'file-import': httpVueLoader('/components/plugins/FileImport.vue')
},
methods: {
clearSearchCnd() {
this.importData = {
fileList: [],
}
this.errorInfoData = {
totalCount: 0,
successCount: 0,
errorCount: 0,
errorList: [],
}
this.pageForm.userIds = []
this.successUserIdList = []
this.doSearch()
this.dialogVisible = false;
$.get('/platform/activity/basic/user/clearSearchCnd', {existsLoginNameRedisKey: this.pageForm.existsLoginNameRedisKey}).then(res => {
if (res.code === 0) {
this.$message.success(res.msg)
} else {
this.$message.error(res.msg)
}
})
},
doImportSearch() {
this.doSearch()
this.dialogVisible = false
},
exportErrors() {
const data = this.errorInfoData.errorList
// 创建工作簿
const workbook = XLSX.utils.book_new();
// 创建工作表
const worksheet = XLSX.utils.json_to_sheet(data);
// 将工作表添加到工作簿
XLSX.utils.book_append_sheet(workbook, worksheet, 'Sheet1');
// 将工作簿转换为二进制对象
const excelBuffer = XLSX.write(workbook, {bookType: 'xlsx', type: 'array'});
// 将二进制对象转换为Blob对象
const blob = new Blob([excelBuffer], {type: 'application/vnd.openxmlformats-officedocument.spreadsheetml.sheet'});
// 创建下载链接并设置相关属性
const url = window.URL.createObjectURL(blob);
const link = document.createElement('a');
link.href = url;
link.download = '核对记录.xlsx';
// 模拟点击下载链接
document.body.appendChild(link);
link.click();
// 清理下载链接
document.body.removeChild(link);
window.URL.revokeObjectURL(url);
},
doImport() {
if (this.importData.fileList.length === 0) {
this.notifyWarning("请选择文件")
return
}
const data = new FormData();
data.append("groupId", this.pageForm.groupId)
this.importData.fileList.forEach((val) => {
data.append("file", val.raw, val.raw.name);
});
this.importLoading = true
$.ajax({
url: "/platform/activity/basic/user/doImport",
type: "post",
data: data,
processData: false,
contentType: false,
success: (data) => {
this.importLoading = false
if (data.code === 0) {
this.notifySuccess("核对成功")
this.errorInfoData = data.data
} else {
this.notifyWarning("核对失败")
}
this.errorInfoData = data.data
this.pageForm.existsLoginNameRedisKey = data.data.existsLoginNameRedisKey
},
error: (data) => {
this.notifyWarning("导入失败")
this.importLoading = false
}
});
},
viewGroupName() {
if (this.pageForm.groupId) {
const group = this.activityGroupList.find(v => v.groupId === this.pageForm.groupId)
this.currentGroupName = group.groupName + '人员'
return
}
this.currentGroupName = '全部人员'
},
doExportUser() {
window.open("/platform/activity/basic/user/doExportUser?groupId=" + this.pageForm.groupId)
},
doSearch2() {
this.getActivityGroup()
this.doSearch()
},
async doDelete(id, groupId) {
const confirm = await this.$confirm('您确定要删除吗?', '提示', {
confirmButtonText: '确定',
cancelButtonText: '取消',
type: 'warning'
})
if (confirm === 'confirm') {
this.pageForm.id=id
this.pageForm.groupId=groupId
const resp = await $.post('/platform/activity/basic/user/doDelete', this.pageForm)
if (resp.code === 0) {
this.$message.success(resp.msg)
this.$set(this.pageForm, "groupId", null)
this.doSearch()
await this.getActivityGroup()
this.$emit('group_change')
}
}
},
async flushUnits() {
this.$set(this.pageForm, "unitId", "")
if (this.is_A06 || this.is_sysadmin || this.is_H03) {
this.units = await getUnits(this.pageForm.unionId)
this.ActivityUnits = await getActivityUnits(this.pageForm.activityUnionId)
} else {
this.units = await getUnits(this.unionid)
}
},
async getActivityGroup() {
this.pageForm.groupId = ''
const resp = await $.get('/platform/activity/basic/scope/getActivityUserScopeGroup')
this.activityGroupList = resp.data
if (resp.data && resp.data.length > 0) {
this.$set(this.pageForm, "groupId", resp.data[0].groupId)
}
await this.pageData()
},
pageOrder(column) {
this.pageForm.pageOrderName = column.prop
this.pageForm.pageOrderBy = column.order
this.pageData()
},
async pageData() {
sublime.showLoadingbar()
const resp = await $.post('/platform/activity/basic/user/pageData', this.pageForm)
if (resp.code === 0) {
this.tableData = resp.data.list
this.pageForm.totalCount = resp.data.totalCount
}
sublime.closeLoadingbar()
},
async getRolesAndUnion() {
const {data} = await $.post("/platform/activity/basic/scope/getRolesAndUnion")
this.roleData = data
}
},
async created() {
this.unions = await getUnions(null)
this.ActivityUnions = await getActivityUnions()
await this.flushUnits()
await this.getActivityGroup()
this.viewGroupName()
await this.getRolesAndUnion()
}
}
</script>
@@ -0,0 +1,915 @@
<template>
<div>
<template>
<el-card shadow="never">
<el-row class="query-row">
<el-col class="query-title">姓名/工号</el-col>
<el-select clearable
v-model="pageForm.userId" filterable remote collapse-tags
placeholder="输入工号或者姓名查找" :remote-method="queryUser" @change="doSearch"
style="width: 100%"
multiple>
<el-option v-for="o in userList"
:label="o.username+'('+o.loginname+')-'+o.unitname" :value="o.id"
:key="o.id"></el-option>
</el-select>
</el-row>
<el-row class="query-row"
v-if="is_H10===true||is_A06===true||is_sysadmin===true||is_H02===true">
<el-col class="query-title hidden-xs-only">会员类型</el-col>
<el-col class="query-content">
<el-tag
:effect="pageForm.memberTypes.includes(item.name)?'dark':'plain'"
:key="item.code"
:type="item.name"
@click="tagClick('memberTypes',item.name)"
style="margin-right: 10px;cursor: pointer"
v-for="item in memberTypeOptions">
{{ item.name }}
</el-tag>
</el-col>
</el-row>
<el-row class="query-row">
<el-col class="query-title hidden-xs-only">性别</el-col>
<el-col class="query-content">
<el-tag
:effect="pageForm.sexTypes.includes(item.name)?'dark':'plain'"
:key="item.code"
:type="item.name"
@click="tagClick('sexTypes',item.name)"
style="margin-right: 10px;cursor: pointer"
v-for="item in sexTypeOptions">
{{ item.name }}
</el-tag>
</el-col>
</el-row>
<el-row class="query-row"
v-if="is_H10===true||is_A06===true||is_sysadmin===true||is_H04===true">
<el-col class="query-title">人员类型</el-col>
<el-col class="query-content">
<el-tag
:effect="pageForm.personTypes.includes(item.name)?'dark':'plain'"
:key="item.code"
:type="item.name"
@click="tagClick('personTypes',item.name)"
style="margin-right: 10px;cursor: pointer"
v-for="item in personTypeOptions">
{{ item.name }}
</el-tag>
<el-link :underline="false" @click="pageForm.personTypes=[];doSearch()"
type="danger"
v-if="personTypeOptions.length&&pageForm.personTypes.length">清空
</el-link>
<el-link :underline="false"
@click="pageForm.personTypes=personTypeOptions.map(p=>p.code);doSearch()"
type="success">全部
</el-link>
</el-col>
</el-row>
<el-row class="query-row"
v-if="is_H10===true||is_A06===true||is_sysadmin===true||is_H04===true">
<el-col class="query-title">在职状态</el-col>
<el-col class="query-content">
<el-tag
:effect="pageForm.userStates.includes(item.name)?'dark':'plain'"
:key="item.code"
:type="item.name"
@click="tagClick('userStates',item.name)"
style="margin-right: 10px;cursor: pointer"
v-for="item in userStateOptions">
{{ item.name }}
</el-tag>
<el-link :underline="false" @click="pageForm.userStates=[];doSearch()"
type="danger"
v-if="userStateOptions.length&&pageForm.userStates.length">清空
</el-link>
<el-link :underline="false"
@click="pageForm.userStates=userStateOptions.map(p=>p.code);doSearch()"
type="success">全部
</el-link>
</el-col>
</el-row>
<el-row class="query-row"
v-if="is_H10===true||is_A06===true||is_sysadmin===true||is_H04===true">
<el-col class="query-title">部门查询</el-col>
<el-col class="query-content">
<el-row :gutter="20">
<el-col :lg="12" :md="12" :sm="24" :xl="12" :xs="24">
<el-select @change="flushUnits();doSearch()"
@clear="flushUnits();doSearch()"
:clearable="is_H10===true||is_A06===true||is_sysadmin===true"
filterable="true"
placeholder="所属工会" style="width: 100%"
v-model="pageForm.unionId">
<el-option :label="item.unionname" :value="item.id"
v-for="item in unions"></el-option>
</el-select>
</el-col>
<el-col :lg="12" :md="12" :sm="24" :xl="12" :xs="24">
<el-select @change="doSearch" @clear="doSearch" clearable="true"
filterable="true"
placeholder="所属单位"
style="width: 100%"
v-model="pageForm.unitId">
<el-option :label="item.name" :value="item.id"
v-for="item in units"></el-option>
</el-select>
</el-col>
</el-row>
</el-col>
</el-row>
<template v-if="is_H10===true||is_A06===true||is_sysadmin===true">
<!--<el-row class="query-row">
<el-col class="query-title">活动部门</el-col>
<el-col class="query-content">
<el-row :gutter="20">
<el-col :lg="12" :md="12" :sm="24" :xl="12" :xs="24">
<el-select @change="flushUnits();doSearch()" @clear="flushUnits();doSearch()"
:clearable="is_A06===true||is_sysadmin===true"
filterable="true"
placeholder="所属工会" style="width: 100%"
v-model="pageForm.activityUnionId">
<el-option :label="item.unionname" :value="item.id"
v-for="item in activityUnions"></el-option>
</el-select>
</el-col>
<el-col :lg="12" :md="12" :sm="24" :xl="12" :xs="24">
<el-select @change="doSearch" @clear="doSearch" clearable="true"
filterable="true"
placeholder="所属单位"
style="width: 100%"
v-model="pageForm.activityUnitId">
<el-option :label="item.name" :value="item.id"
v-for="item in activityUnits"></el-option>
</el-select>
</el-col>
</el-row>
</el-col>
</el-row>-->
<el-row class="query-row">
<el-col class="query-title">系统角色</el-col>
<el-col class="query-content">
<el-row :gutter="20">
<el-col :span="6">
<el-select @change="getRoleListByMenuId" v-model="pageForm.module"
clearable
filterable
style="width: 100%" placeholder="请选择角色所属的系统">
<el-option
:key="item.id"
:label="item.name"
:value="item.id"
v-for="item in menuOptions">
</el-option>
</el-select>
</el-col>
<el-col :span="6" v-if="relatedSessionMenus.includes(pageForm.module)">
<el-select filterable
placeholder="届次"
style="width: 100%"
:disabled="!relatedSessionMenus.includes(pageForm.module)"
v-model="pageForm.teacherMeetingId">
<el-option :key="item.id" :label="item.name"
:value="item.id"
v-for="item in meetingOptions">
</el-option>
</el-select>
</el-col>
<el-col :span="12">
<el-select
@change="doSearch" clearable filterable
placeholder="请选择角色"
multiple
style="width: 100%"
v-model="pageForm.roleIds">
<el-option :label="item.name" :value="item.id"
v-for="item in roleList"></el-option>
</el-select>
</el-col>
</el-row>
</el-col>
</el-row>
</template>
<el-row class="query-row"
v-if="is_H10===true||is_A06===true||is_sysadmin===true||is_H02===true">
<el-col class="query-title">协会</el-col>
<el-col class="query-content">
<el-select v-model="pageForm.clubId" placeholder="请选择协会" @change="doSearch"
filterable
:clearable="is_H10===true||is_A06===true||is_sysadmin===true||(is_H04===true&&is_H02===true)"
style="width: 100%">
<el-option
v-for="item in clubOptions"
:key="item.stid"
:label="item.name"
:value="item.stid">
</el-option>
</el-select>
</el-col>
</el-row>
<el-row class="query-row">
<el-col class="query-title">活动组别</el-col>
<el-col class="query-content">
<el-select @change="doSearch()" placeholder="请选择活动组别范围之外的人员" clearable
style="width: 100%" v-model="pageForm.activityGroupId">
<el-option :label="item.groupName"
:value="item.groupId"
v-for="item in activityGroupList2"></el-option>
</el-select>
</el-col>
</el-row>
<el-row class="query-row"
v-if="is_H10===true||is_A06===true||is_sysadmin===true||is_H04===true">
<el-col class="query-title">年龄范围</el-col>
<el-col class="query-content">
<el-row type="flex" style="align-items: center">
<el-col :span="15">
<el-slider
v-model="pageForm.age"
range
show-stops
:max="100">
</el-slider>
</el-col>
<el-col :span="9" class="pl20">
当前范围{{ pageForm.age }}
</el-col>
</el-row>
</el-col>
</el-row>
<el-row class="query-row"
v-if="is_H10===true||is_A06===true||is_sysadmin===true||is_H04===true">
<el-col class="query-title">条件匹配</el-col>
<el-col class="query-content">
<user-cnd @cnd="(v)=>{this.$set(this.pageForm,'activityUserCnd',v)}"></user-cnd>
</el-col>
</el-row>
<el-row class="query-row" style="justify-content: end">
<el-checkbox v-model="pageForm.reverseSelection" label="是否反选" border
@change="doSearch"
class="reverseCheckBox"></el-checkbox>
<el-button type="danger" icon="el-icon-circle-close" @click="doReset">重置
</el-button>
<el-button type="primary" icon="el-icon-search" @click="doSearch">搜索</el-button>
</el-row>
</el-card>
<el-card class="mt10" shadow="never">
<table-tool :app="this" label="筛选人员">
<template #func>
<el-button v-if="is_sysadmin||is_A06"
type="primary" size="medium" icon="el-icon-printer" @click="dialogVisible = true">
导入XLSX设置分组
</el-button>
<el-button @click="doExportUser"
size="medium"
type="primary" icon="el-icon-download">
导出查询人员
</el-button>
<el-button @click="setDialogVisible=true"
size="medium"
type="primary">
设置为活动人员
</el-button>
</template>
</table-tool>
<el-table :data="tableData" :size="tableSize" @sort-change="pageOrder" border
ref="userTable" stripe>
<el-table-column label="序号" type="index" width="80px"></el-table-column>
<el-table-column
:label="column.label"
:prop="column.prop"
:sortable="column.sortable"
align="center"
header-align="center"
show-overflow-tooltip
v-for="column in tableColumns"
></el-table-column>
</el-table>
<el-row class="el-pagination-container">
<el-pagination
@size-change="pageSizeChange"
@current-change="pageNumberChange"
:current-page="pageForm.pageNumber"
:page-size="pageForm.pageSize"
layout="total, prev, pager, next"
:total="pageForm.totalCount">
</el-pagination>
</el-row>
</el-card>
</template>
<el-dialog :visible.sync="setDialogVisible" title="设置活动人员" width="45%" :append-to-body="true"
:close-on-click-modal="false">
<el-form :model="formData" :rules="rules" label-width="100px" ref="setForm">
<el-form-item label="添加方式" prop="setGroupType">
<el-radio-group size="small" v-model="formData.setGroupType">
<el-radio :label="1">添加至原有分组</el-radio>
<el-radio :label="2">添加到新分组</el-radio>
</el-radio-group>
</el-form-item>
<el-row v-if="formData.setGroupType===1">
<el-form-item label="原有分组" prop="setGroupId">
<el-radio-group size="small" v-model="formData.setGroupId">
<el-radio :disabled="item.groupId!=pageForm.activityGroupId" :label="item.groupId"
border v-for="item in activityGroupList">
{{ item.groupName }}
</el-radio>
</el-radio-group>
</el-form-item>
</el-row>
<el-row v-if="formData.setGroupType===2">
<el-form-item label="新分组" prop="setGroupName">
<el-input placeholder="请输入新分组名称" v-model="formData.setGroupName"></el-input>
</el-form-item>
</el-row>
</el-form>
<span class="dialog-footer" slot="footer">
<el-button @click="setDialogVisible = false"> </el-button>
<el-button @click="doSetActivityUser" type="primary"
v-loading="settingLoading"> </el-button>
</span>
</el-dialog>
<el-dialog title="人员导入" :visible.sync="dialogVisible" width="50%" :close-on-click-modal="false" append-to-body>
<el-timeline>
<el-timeline-item timestamp="下载模板" placement="top">
<el-card>
<el-button size="medium" type=""
@click="window.open('/platform/activity/basic/user/downloadImport')"
icon="el-icon-download">下载模板
</el-button>
</el-card>
</el-timeline-item>
<el-timeline-item timestamp="上传文件" placement="top">
<el-card>
<el-upload
name="file"
ref="upload"
:on-remove="(file, fileList) => {
importData.fileList = fileHandleRemove(file, fileList)
}"
:on-change="(file, fileList) => {
importData.fileList = fileHandleChange(file, fileList,{type:['xls','xlsx']})
}"
:auto-upload="false"
:limit="1"
:file-list="importData.fileList">
<el-button size="medium" type="" icon="el-icon-upload"
style="width: 200px">选择文件
</el-button>
<div class="el-upload__tip" slot="tip" style="color: #F56C6C">
只能上传 xls/xlsx 文件
</div>
</el-upload>
</el-card>
</el-timeline-item>
<el-timeline-item placement="top" timestamp="导入结果">
<el-card shadow="never">
<p>总记录数:{{ errorInfoData.totalCount }}</p>
<p>成功数:<span class="text-success">{{ errorInfoData.successCount }}</span></p>
<p>错误数:<span class="text-danger">{{ errorInfoData.errorCount }}</span></p>
<el-link @click="exportErrors" type="primary" v-if="errorInfoData.errorCount>0">下载错误记录
</el-link>
</el-card>
</el-timeline-item>
</el-timeline>
<span slot="footer" class="dialog-footer">
<el-button @click="dialogVisible = false" type="primary"
:disabled="importLoading">取 消</el-button>
<el-button type="primary" @click="clearSearchCnd"
:loading="importLoading">清空查询条件</el-button>
<el-button type="primary" @click="doImport" :loading="importLoading">核对人员</el-button>
<el-button type="primary" @click="doImportSearch"
:loading="importLoading">查询人员</el-button>
</span>
</el-dialog>
</div>
</template>
<script>
module.exports = {
props: {},
model: {},
mixins: [initTableMixins],
data() {
return {
userList: [],
clubOptions: [],
settingLoading: false,
setDialogVisible: false,
setGroupType: null,
setGroupId: null,
setGroupName: null,
personTypeOptions: [],
userStateOptions: [],
activityGroupList: [],
activityGroupList2: [],
memberTypeOptions: [{
code: 'unionMember',
name: '工会会员'
}, {
code: 'welfareMember',
name: '福利会员'
}, {
code: 'sickFundMember',
name: '基金会员'
}],
sexTypeOptions: [
{code: '男', name: '男'},
{code: '女', name: '女'}
],
pageForm: {
age: [0, 0],
unionId: '',
unitId: '',
clubId: '',
searchName: "u.username",
personTypes: [],
userStates: [],
memberStatus: [],
memberTypes: [],
sexTypes: [],
minAge: 0,
maxAge: 0,
year: moment().format('YYYY'),
module: '',
teacherMeetingId: '',
activityGroupId: '',
roleIds: [],
userId: [],
activityUserCnd: '',
reverseSelection: false
},
activityUnions: [],
unions: [],
units: [],
activityUnits: [],
menuOptions: [],
meetingOptions: [],
roleList: [],
tableHeight: '0px',
tableColumns: [
{prop: 'loginName', label: '工号'},
{prop: 'userName', label: '姓名'},
{prop: 'sex', label: '性别'},
{prop: 'birthday', label: '出生年月', sortable: true},
{prop: 'age', label: '年龄', sortable: true},
{prop: 'mobile', label: '联系电话'},
{prop: 'personType', label: '人员类型', sortable: true},
{prop: 'userState', label: '在职状态', sortable: true},
{prop: 'unitName', label: '所属单位', sortable: true},
{prop: 'unionName', label: '所属工会', sortable: true},
// {prop: 'activityUnionName', label: '活动工会', sortable: true},
],
rules: {
setGroupType: [{required: true, message: '请选择添加方式', trigger: ['blur', 'change']}],
setGroupId: [{required: true, message: '请选择分组', trigger: ['blur', 'change']}],
setGroupName: [{required: true, message: '请输入分组名称', trigger: ['blur', 'change']}]
},
relatedSessionMenus: ['aca4d14498c145ceb5b24ed70776aae2', '733d7266652740a3aeac9da97ab5eeca', 'fe2d0768e26d4a80beeb159306bb8d01'],
roleData: {},
dialogVisible: false,
importLoading: false,
importData: {
fileList: [],
},
errorInfoData: {
totalCount: 0,
successCount: 0,
errorCount: 0,
errorList: 0,
},
}
},
computed: {
is_H10() {
return this.roleData.is_H10
},
is_A06() {
return this.roleData.is_A06
},
is_H04() {
return this.roleData.is_H04
},
is_H02() {
return this.roleData.is_H02
},
is_sysadmin() {
return this.roleData.is_sysadmin
},
unionid() {
return this.roleData.unionid
},
},
components: {
'user-cnd': httpVueLoader('/components/plugins/UserCnd.vue'),
},
methods: {
exportErrors() {
const data = this.errorInfoData.errorList
// 创建工作簿
const workbook = XLSX.utils.book_new();
// 创建工作表
const worksheet = XLSX.utils.json_to_sheet(data);
// 将工作表添加到工作簿
XLSX.utils.book_append_sheet(workbook, worksheet, 'Sheet1');
// 将工作簿转换为二进制对象
const excelBuffer = XLSX.write(workbook, {bookType: 'xlsx', type: 'array'});
// 将二进制对象转换为Blob对象
const blob = new Blob([excelBuffer], {type: 'application/vnd.openxmlformats-officedocument.spreadsheetml.sheet'});
// 创建下载链接并设置相关属性
const url = window.URL.createObjectURL(blob);
const link = document.createElement('a');
link.href = url;
link.download = '核对记录.xlsx';
// 模拟点击下载链接
document.body.appendChild(link);
link.click();
// 清理下载链接
document.body.removeChild(link);
window.URL.revokeObjectURL(url);
},
doImportSearch() {
this.doSearch()
this.dialogVisible = false
},
doImport() {
if (this.importData.fileList.length === 0) {
this.notifyWarning("请选择文件")
return
}
const data = new FormData();
this.importData.fileList.forEach((val) => {
data.append("file", val.raw, val.raw.name);
});
this.importLoading = true
$.ajax({
url: "/platform/activity/basic/scope/doImport",
type: "post",
data: data,
processData: false,
contentType: false,
success: (data) => {
this.importLoading = false
if (data.code === 0) {
this.notifySuccess("核对成功")
this.errorInfoData = data.data
} else {
this.notifyWarning("核对失败")
}
this.errorInfoData = data.data
this.pageForm.existsLoginNameRedisKey = data.data.existsLoginNameRedisKey
},
error: (data) => {
this.notifyWarning("导入失败")
this.importLoading = false
}
});
},
clearSearchCnd() {
this.importData = {
fileList: [],
}
this.errorInfoData = {
totalCount: 0,
successCount: 0,
errorCount: 0,
errorList: [],
}
this.pageForm.userIds = []
this.successUserIdList = []
this.doSearch()
this.dialogVisible = false;
$.get('/platform/activity/basic/scope/clearSearchCnd', {existsLoginNameRedisKey: this.pageForm.existsLoginNameRedisKey}).then(res => {
if (res.code === 0) {
this.$message.success(res.msg)
} else {
this.$message.error(res.msg)
}
})
},
doExportUser() {
const {
userId,
memberTypes,
sexTypes,
personTypes,
userStates,
unionId,
unitId,
teacherMeetingId,
roleIds,
clubId,
activityGroupId,
age,
reverseSelection,
activityUserCnd,
existsLoginNameRedisKey
} = this.pageForm
let props = {}
this.tableColumns.forEach(v => {
props[v.prop] = v.label
})
window.open("/platform/activity/basic/scope/doExportUser?userId=" + JSON.stringify(userId) +
"&props=" + JSON.stringify(props) +
"&memberTypes=" + JSON.stringify(memberTypes) +
"&sexTypes=" + JSON.stringify(sexTypes) +
"&personTypes=" + JSON.stringify(personTypes) +
"&userStates=" + JSON.stringify(userStates) +
"&roleIds=" + JSON.stringify(roleIds) +
"&age=" + JSON.stringify(age) +
"&activityUserCnd=" + (activityUserCnd ? JSON.stringify(activityUserCnd) : activityUserCnd) +
"&reverseSelection=" + reverseSelection +
"&clubId=" + clubId +
"&activityGroupId=" + activityGroupId +
"&teacherMeetingId=" + teacherMeetingId +
"&unionId=" + unionId +
"&unitId=" + unitId+
"&existsLoginNameRedisKey=" + existsLoginNameRedisKey
)
},
doReset() {
this.pageForm.userId = []
this.pageForm.memberTypes = []
this.pageForm.sexTypes = []
this.pageForm.personTypes = []
this.pageForm.userStates = []
this.pageForm.unionId = ''
this.pageForm.unitId = ''
this.pageForm.module = ''
this.pageForm.teacherMeetingId = ''
this.pageForm.roleIds = []
this.pageForm.clubId = ''
this.pageForm.activityGroupId = ''
this.pageForm.activityUserCnd = ''
this.pageForm.age = [0, 0]
this.pageForm.reverseSelection = false
this.doSearch()
},
async queryUser(val) {
this.userList = await searchUser(val)
},
tagClick(key, val) {
let idx = this.pageForm[key].indexOf(val)
if (idx !== -1) {
this.pageForm[key].splice(idx, 1)
} else {
this.pageForm[key].push(val)
}
this.doSearch()
},
async flushUnits() {
this.$set(this.pageForm, "unitId", "")
if (this.is_sysadmin || this.is_A06) {
this.units = await getUnits(this.pageForm.unionId)
this.activityUnits = await getActivityUnits(this.pageForm.activityUnionId)
} else {
this.units = await getUnits(this.unionid)
}
},
async pageData() {
sublime.showLoadingbar()
const pageForm = clone(this.pageForm)
pageForm.personTypes = JSON.stringify(pageForm.personTypes)
pageForm.userStates = JSON.stringify(pageForm.userStates)
pageForm.memberStatus = JSON.stringify(pageForm.memberStatus)
pageForm.memberTypes = JSON.stringify(pageForm.memberTypes)
pageForm.sexTypes = JSON.stringify(pageForm.sexTypes)
pageForm.roleIds = JSON.stringify(pageForm.roleIds)
pageForm.userId = JSON.stringify(pageForm.userId)
pageForm.age = JSON.stringify(pageForm.age)
pageForm.activityUserCnd = pageForm.activityUserCnd ? JSON.stringify(pageForm.activityUserCnd) : pageForm.activityUserCnd
const resp = await $.post('/platform/activity/basic/scope/pageData', pageForm)
sublime.closeLoadingbar()
if (resp.code === 0) {
this.tableData = resp.data.list
this.pageForm.totalCount = resp.data.totalCount
} else {
this.notifyWarning(resp.msg)
}
},
async doSetActivityUser() {
const valid = await this.$refs.setForm.validate()
if (!valid) {
return
}
if (this.tableData.length === 0) {
this.$message.warning('请先指定筛选条件!')
return
}
const confirm = await this.$confirm('是否将符合搜索条件的用户设为活动人员?', '提示', {
confirmButtonText: '确定',
cancelButtonText: '取消',
type: 'warning'
})
if (confirm === 'confirm') {
this.settingLoading = true
const pageForm = clone(this.pageForm)
pageForm.personTypes = JSON.stringify(pageForm.personTypes)
pageForm.userStates = JSON.stringify(pageForm.userStates)
pageForm.memberStatus = JSON.stringify(pageForm.memberStatus)
pageForm.memberTypes = JSON.stringify(pageForm.memberTypes)
pageForm.sexTypes = JSON.stringify(pageForm.sexTypes)
pageForm.roleIds = JSON.stringify(pageForm.roleIds)
pageForm.userId = JSON.stringify(pageForm.userId)
pageForm.age = JSON.stringify(pageForm.age)
pageForm.activityUserCnd = pageForm.activityUserCnd ? JSON.stringify(pageForm.activityUserCnd) : pageForm.activityUserCnd
Object.assign(pageForm, this.formData)
const resp = await $.post('/platform/activity/basic/scope/doSetActivityUser', pageForm)
if (resp.code === 0) {
this.setDialogVisible = false
// this.userScopeDialog = false
await this.getActivityGroup()
this.doSearch()
this.notifySuccess(resp.msg)
this.formData = {
setGroupType: null,
setGroupId: null,
setGroupName: null
}
} else {
this.notifyError(resp.msg)
}
this.settingLoading = false
this.$emit("update:group_id", resp.data)
this.$emit('group_change')
}
},
async getActivityGroup() {
const resp = await $.get('/platform/activity/basic/scope/getActivityUserScopeGroup')
this.activityGroupList = resp.data
this.activityGroupList2 = []
resp.data.forEach(v => {
this.activityGroupList2.push({groupId: v.groupId, groupName: v.groupName + "范围之外人员"})
})
},
async getMenuOptions() {
const {data} = await $.get("/platform/sys/role/getMenuOptions")
this.menuOptions = data
},
async getRoleListByMenuId() {
if (['aca4d14498c145ceb5b24ed70776aae2', '733d7266652740a3aeac9da97ab5eeca'].includes(this.pageForm.module)) {
//教代会
let meets = await proposal.getOpenMeeting()
this.meetingOptions = meets.map(v => ({...v, name: v.jdhallname}))
} else if (['fe2d0768e26d4a80beeb159306bb8d01'].includes(this.pageForm.module)) {
//工代会
let meets = await getGdh(true)
this.meetingOptions = meets.map(v => ({...v, name: v.gdhAllName}))
}
this.pageForm.teacherMeetingId = ''
const {data} = await $.post("/platform/activity/basic/scope/getRoleListByMenuId", {menuId: this.pageForm.module})
this.roleList = data
},
async getRolesAndUnion() {
const {data} = await $.post("/platform/activity/basic/scope/getRolesAndUnion")
this.roleData = data
}
},
async created() {
await this.getRolesAndUnion()
this.clubOptions = await getClubsByRole()
if (((this.is_sysadmin || this.is_A06 || this.is_H02) === false) && this.is_H04 === true) {
this.unions = await getUnionList(this.unionid)
this.$set(this.pageForm, "unionId", this.unions[0].id)
} else {
this.unions = await getUnions(null)
this.activityUnions = await getActivityUnions()
}
if (this.is_H04 === false && this.is_H02 === true) {
if (this.clubOptions.length > 0) {
this.$set(this.pageForm, "clubId", this.clubOptions[0].stid)
}
}
await this.flushUnits()
await this.getActivityGroup()
this.personTypeOptions = await getDictOptions("UserType")
this.userStateOptions = await getDictOptions("UserState")
await this.getMenuOptions()
await this.pageData()
},
}
</script>
<style>
.query-row {
display: flex;
align-items: center;
padding: 6px 0;
}
.query-row:not(:last-child) {
border-bottom: 1px dashed rgb(230, 230, 230);
}
.query-row > .query-title {
width: 100px;
max-width: 100px;
min-width: 100px;
overflow: hidden;
}
.query-row > .query-content {
min-width: 200px;
overflow: hidden;
}
.query-row > .query-content > .el-tag {
margin-bottom: 5px;
margin-top: 5px;
}
@media screen and (max-width: 992px) {
.query-row:nth-child(4) .query-content .el-col:not(:last-child) {
margin-bottom: 5px;
}
.query-title {
display: none;
}
}
.header_card .el-card__body {
padding: 2px 20px;
}
.user_card .el-card__body {
padding: 2px 20px;
}
.user_card {
border: none !important;
}
.user_table {
max-height: 260px;
}
.user_table .el-table__cell {
padding: 0;
}
.el-pagination {
height: 40px;
}
.el-popover {
height: 250px;
}
.reverseCheckBox {
margin: 0 10px 0 0 !important;
}
</style>
@@ -0,0 +1,157 @@
<template>
<el-timeline>
<el-timeline-item timestamp="" placement="top">
<el-input placeholder="请输入内容" clearable v-model="pageForm.searchKeyword"
@keyup.enter.native="doSearch" style="width: 300px">
<el-select v-model="pageForm.searchName" slot="prepend" style="width: 80px;">
<el-option label="姓名" value="username"></el-option>
<el-option label="工号" value="loginname"></el-option>
</el-select>
</el-input>
<el-button type="primary" icon="el-icon-search" @click="doSearch"></el-button>
</el-timeline-item>
<el-timeline-item timestamp="" placement="top">
<el-table :data="tableData" style="width: 100%" row-key="id"
v-loading="tableLoading" ref="table" class="vi-table"
@selection-change="handleSelectionChange">
<el-table-column type="selection" :reserve-selection="true"></el-table-column>
<el-table-column
align="center"
header-align="center"
v-for="column in columns"
show-overflow-tooltip
:sortable="column.sortable"
:label="column.label"
:prop="column.prop" :width="column.width">
</el-table-column>
</el-table>
<el-row class="el-pagination-container">
<el-pagination
@size-change="pageSizeChange"
@current-change="pageNumberChange"
:current-page="pageForm.pageNumber"
:page-size="pageForm.pageSize"
layout="total, prev, pager, next"
:total="pageForm.totalCount">
</el-pagination>
</el-row>
</el-timeline-item>
</el-timeline>
</template>
<script>
module.exports = {
props: {
value: {type: Array},
columns: {
type: Array,
default: [{
prop: 'loginname',
label: '工号',
}, {
prop: 'username',
label: '姓名',
}, {
prop: 'sex',
label: '性别',
}, {
prop: 'mobile',
label: '电话',
}, {
prop: 'unitname',
label: '单位',
}, {
prop: 'unionname',
label: '工会',
}]
},
union: {type: String},
page_size: {type: Number, default: 5},
sql_cnd: {
type: Array
}
},
model: {
prop: 'value',
event: 'change'
},
data() {
return {
tableData: [],
tableLoading: false,
selectUser: [],
pageForm: {
unionId: this.union,
sqlCnd: JSON.stringify(this.sql_cnd),
searchName: "username",
searchKeyword: "",
pageNumber: 1,
pageSize: this.page_size,
totalCount: 0,
pageOrderName: "",
pageOrderBy: ""
}
}
},
watch: {
value(val) {
}
},
methods: {
handleSelectionChange(val) {
this.selectUser = val
this.$emit("change", val.map(v => v.id))
},
doSearch() {
this.tableKey = new Date().getTime()
this.pageForm.pageNumber = 1
this.pageData()
},
pageOrder(column) {
this.pageForm.pageOrderName = column.prop;
this.pageForm.pageOrderBy = column.order;
this.pageData();
},
pageNumberChange(val) {
this.pageForm.pageNumber = val;
this.pageData();
},
pageSizeChange(val) {
this.pageForm.pageSize = val;
this.pageData();
},
pageData() {
this.tableLoading = true
$.post("/platform/common/user/userPageData", this.pageForm, (data) => {
this.tableLoading = false
if (data.code == 0) {
this.tableData = data.data.list;
this.pageForm.totalCount = data.data.totalCount;
this.tableData.filter(v => this.value.includes(v.id) && !this.selectUser.some(x => x.id == v.id)).forEach(v => {
this.$refs.table.toggleRowSelection(v, true);
})
} else {
this.$message.error(data.msg);
}
}, "json");
},
init() {
this.doSearch()
this.selectUser = []
this.$refs.table.clearSelection();
},
},
created() {
}
}
</script>
<style>
</style>
@@ -0,0 +1,664 @@
<template>
<van-uploader v-model="fileList" multiple
:after-read="afterRead"
@delete="doDelete"
:max-count="max"
:show-upload="!view"
:deletable="!view"
:max-size="max_size"
@oversize="onOversize"
@click-preview="clickPreview"
:before-read="beforeRead"
>
</van-uploader>
</template>
<script>
/**
* 文件类型解析
* @type {{isImg: wpUploadFileTypeResolve.isImg}}
*/
let fileTypeResolving = {
/**
* 是否是一张图片
*/
isImg: function (fileItem) {
return fileTypeResolving.resolvingByType(fileItem.type, /image\/(\w)*/)
},
/**
* 通过后缀验证图片
*/
isImgByName: function (fileItemName) {
let checkSuffixArray = ['jpg', 'png', 'jpeg', 'bmp', 'gif', 'webp', 'tif', 'svg', 'wmf'];
return fileTypeResolving.resolvingByName(fileItemName, checkSuffixArray)
},
/**
* 是否是视频
*/
isVideo: function (fileItem) {
return fileTypeResolving.resolvingByType(fileItem.type, /video\/(\w)*/)
},
/**
* 通过后缀验证图片
*/
isVideoByName: function (fileItemName) {
let checkSuffixArray = ['mp4', 'Ogg', 'webm'];
return fileTypeResolving.resolvingByName(fileItemName, checkSuffixArray)
},
/**
* 是否是音频
*/
isAudio: function (fileItem) {
return fileTypeResolving.resolvingByType(fileItem.type, /audio\/(\w)*/)
},
/**
* 通过后缀验证图片
*/
isAudioByName: function (fileItemName) {
let checkSuffixArray = ['mp3', 'ogg', 'wav'];
return fileTypeResolving.resolvingByName(fileItemName, checkSuffixArray)
},
/**
* 是否是doc文件
*/
isDoc: function (fileItemName) {
let checkSuffixArray = ['doc', 'docx', 'dot', 'dotx'];
return fileTypeResolving.resolvingByName(fileItemName, checkSuffixArray);
},
/**
* 是否是excel文件
*/
isExcel: function (fileItemName) {
let checkSuffixArray = ['xls', 'xlsx', 'csv', 'xlt', 'xltx'];
return fileTypeResolving.resolvingByName(fileItemName, checkSuffixArray);
},
/**
* 是否是PPT文件
*/
isPPT: function (fileItemName) {
let checkSuffixArray = ['ppt', 'pptx', 'pot', 'potx', 'odp'];
return fileTypeResolving.resolvingByName(fileItemName, checkSuffixArray);
},
/**
* 是否是Pdf文件
*/
isPdf: function (fileItemName) {
let checkSuffixArray = ['pdf'];
return fileTypeResolving.resolvingByName(fileItemName, checkSuffixArray);
},
/**
* 是否是压缩文件
* @param fileItem
* @returns {boolean}
*/
isZip: function (fileItemName) {
let checkSuffixArray = ['zip', '7z', 'war', 'tar', 'rar', 'jar', 'zipx', 'zix', 'zoo'];
return fileTypeResolving.resolvingByName(fileItemName, checkSuffixArray);
},
isWeb: function (fileItemName) {
let checkSuffixArray = ['html', 'htm'];
return fileTypeResolving.resolvingByName(fileItemName, checkSuffixArray);
},
isTxt: function (fileItemName) {
let checkSuffixArray = ['txt'];
return fileTypeResolving.resolvingByName(fileItemName, checkSuffixArray);
},
isPsd: function (fileItemName) {
let checkSuffixArray = ['psd'];
return fileTypeResolving.resolvingByName(fileItemName, checkSuffixArray);
},
isCad: function (fileItemName) {
let checkSuffixArray = ['cad'];
return fileTypeResolving.resolvingByName(fileItemName, checkSuffixArray);
},
isIso: function (fileItemName) {
let checkSuffixArray = ['iso'];
return fileTypeResolving.resolvingByName(fileItemName, checkSuffixArray);
},
isExe: function (fileItemName) {
let checkSuffixArray = ['exe'];
return fileTypeResolving.resolvingByName(fileItemName, checkSuffixArray);
},
/**
* 根据文件类型来解析
* @param fileType 文件类型
* @param checkTypeModel 文件类型模型,如:image\/(\w)*
* @returns {boolean}
*/
resolvingByType: function (fileType, checkTypeModel) {
if (checkTypeModel.test(fileType)) {
return true;
}
return false;
},
/**
* 根据名字和名字后缀名来验证文件
* @param fileName 文件名
* @param checkSuffixArray 文件类型包含的后缀
*/
resolvingByName: function (fileName, checkSuffixArray) {
let suffixName = wpUploadFileTools.getSuffixNameByFileName(fileName);
// 名字是否有效
if (!wpUploadDataValid.isValidStr(suffixName)) {
// 无效直接返回false
return false;
}
suffixName = suffixName.trim();
suffixName = suffixName.toLowerCase();
if (checkSuffixArray.indexOf(suffixName) != -1) {
return true;
}
return false;
}
}
/**
* 文件工具
* @type {{}}
*/
let wpUploadFileTools = {
/**
* 获取文件显示模版
* @param fileItem
*/
wapFileItemShow: function (fileItem) {
return wpUploadFileTools.wapFileItemShowBase(fileItem, false);
},
/**
* 包装已上传的文件列表
*/
wapFileItemShowWithUpload(uploadFile) {
return wpUploadFileTools.wapFileItemShowBase(uploadFile, true);
},
/**
* 获取文件显示的基本操作
*/
wapFileItemShowBase(fileItem, isUploaded = false) {
let fileName = "";
let suffix = "";
let show = "";
let showIcon = "";
if (!isUploaded) {
fileName = fileItem.name;
suffix = wpUploadFileTools.getSuffixNameByFileName(fileName);
show = wpUploadFileTools.resolvingShow(fileItem);
showIcon = wpUploadFileShowResolving.getFileItemShowIcon(show, fileItem, false);
} else {
fileName = fileItem.name ? fileItem.name : wpUploadFileTools.resolvingUrlFileName(fileItem.url);
let fileNameGetOFuRL = wpUploadFileTools.resolvingUrlFileName(fileItem.url);
suffix = wpUploadFileTools.getSuffixNameByFileName(fileNameGetOFuRL);
show = wpUploadFileTools.resolvingShowByFileName(fileNameGetOFuRL);
showIcon = wpUploadFileShowResolving.getFileItemShowIcon(show, fileItem.url, true);
}
let fileItemShow = {
// 文件的id
id: wpUploadFileTools.uuid(),
// 文件对象
file: null,
// 文件的类型
type: null,
// 文件的大小
size: null,
// 文件的名字
name: fileName,
// 文件地址
url: null,
// 后缀
suffix: suffix,
// 显示的类型
show: show,
// 显示的图标或者图片地址
showIcon: showIcon,
// 显示进度条
processStatus: {
show: false,
width: 0,
isFail: false
},
// 文件来源,0选择文件上传,1回显文件
fileSource: 0,
// 状态0未上传,失败也会转到0,1正在上传,2已经上传
status: 0,
// 上传文件的描述
fileDes: null
}
if (!isUploaded) {
// 如果非选择文件下面三个属性为null
fileItemShow.file = fileItem;
fileItemShow.type = fileItem.type;
fileItemShow.size = fileItem.size;
} else {
// 文件描述
fileItemShow.status = 2;
fileItemShow.fileDes = fileItem;
fileItemShow.fileSource = 1;
fileItemShow.url = fileItem.url;
}
return fileItemShow;
},
/**
* 解析URL的文件名字
*/
resolvingUrlFileName: function (fileUrl) {
let index = fileUrl.lastIndexOf("/");
if (index <= 0) {
index = fileUrl.lastIndexOf("\\");
}
index = index + 1;
let fileName = fileUrl.substring(index, fileUrl.length);
return fileName;
},
/**
* 获取文件名后缀
* @param fileName 文件名全名
* */
getSuffixNameByFileName: function (fileName) {
let str = fileName;
let index = str.lastIndexOf(".");
if (index < 0) {
return "";
}
let pos = index + 1;
return str.substring(pos, str.length);
},
/**
* 解析显示类型
* @param fileItem 文件
* @returns {number}
*/
resolvingShow: function (fileItem) {
// 默认0普通文件
let showResult = 0;
if (wpUploadFileTypeResolving.isImg(fileItem)) {
showResult = 1;
} else if (wpUploadFileTypeResolving.isVideo(fileItem)) {
showResult = 2;
} else if (wpUploadFileTypeResolving.isAudio(fileItem)) {
showResult = 3;
} else if (wpUploadFileTypeResolving.isDoc(fileItem.name)) {
showResult = 4;
} else if (wpUploadFileTypeResolving.isExcel(fileItem.name)) {
showResult = 5;
} else if (wpUploadFileTypeResolving.isPPT(fileItem.name)) {
showResult = 6;
} else if (wpUploadFileTypeResolving.isPdf(fileItem.name)) {
showResult = 7;
} else if (wpUploadFileTypeResolving.isZip(fileItem.name)) {
showResult = 8;
} else if (wpUploadFileTypeResolving.isWeb(fileItem.name)) {
showResult = 9;
} else if (wpUploadFileTypeResolving.isTxt(fileItem.name)) {
showResult = 10;
} else if (wpUploadFileTypeResolving.isPsd(fileItem.name)) {
showResult = 11;
} else if (wpUploadFileTypeResolving.isCad(fileItem.name)) {
showResult = 12;
} else if (wpUploadFileTypeResolving.isIso(fileItem.name)) {
showResult = 13;
} else if (wpUploadFileTypeResolving.isExe(fileItem.name)) {
showResult = 14;
}
return showResult
},
/**
* 解析显示类型
* @param fileItem 文件
* @returns {number}
*/
resolvingShowByFileName: function (fileItemName) {
// 默认0普通文件
let showResult = 0;
if (wpUploadFileTypeResolving.isImgByName(fileItemName)) {
showResult = 1;
} else if (wpUploadFileTypeResolving.isVideoByName(fileItemName)) {
showResult = 2;
} else if (wpUploadFileTypeResolving.isAudioByName(fileItemName)) {
showResult = 3;
} else if (wpUploadFileTypeResolving.isDoc(fileItemName)) {
showResult = 4;
} else if (wpUploadFileTypeResolving.isExcel(fileItemName)) {
showResult = 5;
} else if (wpUploadFileTypeResolving.isPPT(fileItemName)) {
showResult = 6;
} else if (wpUploadFileTypeResolving.isPdf(fileItemName)) {
showResult = 7;
} else if (wpUploadFileTypeResolving.isZip(fileItemName)) {
showResult = 8;
} else if (wpUploadFileTypeResolving.isWeb(fileItemName)) {
showResult = 9;
} else if (wpUploadFileTypeResolving.isTxt(fileItemName)) {
showResult = 10;
} else if (wpUploadFileTypeResolving.isPsd(fileItemName)) {
showResult = 11;
} else if (wpUploadFileTypeResolving.isCad(fileItemName)) {
showResult = 12;
} else if (wpUploadFileTypeResolving.isIso(fileItemName)) {
showResult = 13;
} else if (wpUploadFileTypeResolving.isExe(fileItemName)) {
showResult = 14;
}
return showResult
},
/**
* 生成UUID
* @returns {string}
*/
uuid: function () {
let str = wpUploadFileTools.uuidFull();
str = str.replace(/-/g, "");
return str;
},
uuidFull() {
let s = []
let hexDigits = "0123456789abcdef"
for (var i = 0; i < 36; i++) {
s[i] = hexDigits.substr(Math.floor(Math.random() * 0x10), 1)
}
s[14] = "4"
s[19] = hexDigits.substr((s[19] & 0x3) | 0x8, 1)
s[8] = s[13] = s[18] = s[23] = "-"
let uuid = s.join("")
return uuid
},
/**
* 禁止某个dom的某个事件
*/
disableObjEvent(domObj, eventName) {
domObj.addEventListener(eventName, function (e) {
e.preventDefault();
})
}
}
/**
* 数据验证工具
* @type {{isValid: wpUploadDataValid.isValid}}
*/
let wpUploadDataValid = {
isValid: function (obj) {
if (undefined === obj || null === obj) {
return false;
}
return true;
},
isValidStr: function (str) {
let isValidObj = wpUploadDataValid.isValid(str);
if (!isValidObj) {
return isValidObj;
}
str = str.trim();
if ("" == str || '' == str) {
return false;
}
return true;
},
isValidArray(array) {
if (null == array || array == undefined || array.length <= 0) {
return false;
}
return true;
}
}
module.exports = {
props: {
files: Array,
type: {
type: Array,
default: ['jpg', 'jpeg', 'png', 'doc', 'docx', 'xls', 'xlsx', 'pdf']
},
max: {
type: Number,
default: 10
},
max_size: {
type: Number,
default: 100 * 1024 * 1024
},
view: {
type: Boolean,
default: false
},
del: {
type: Boolean,
default: true
}
},
data() {
return {
fileList: []
}
},
watch: {
files(val) {
this.updateFileList(val)
}
},
methods: {
// 返回布尔值
beforeRead(file) {
const type = this.type.includes(file.name.split('.')[1].toLowerCase());
if (!type) {
this.$toast(`上传文件只能是 ${this.type.map(v => v.toLowerCase()).join("/")} 格式!`);
return false;
}
return true;
},
getAccept() {
return this.type.map(v => '.' + v).join(",")
},
onOversize() {
this.$toast(`上传文件大小不能超过 ${this.max_size / 1024 / 1024} MB!`);
},
/**
* 查看资源
*/
showSource(showItem) {
const show = this.resolvingShowByFileName(showItem.filepath)
if (show == 1 || show == 2 || show == 3) {
$('.viewFile').viewer({
url: 'src',
});
} else if (show == 4 || show == 5 || show == 7) {
preview(showItem.filepath, showItem.id)
}
},
/**
* 解析显示类型
* @param fileItem 文件
* @returns {number}
*/
resolvingShowByFileName(fileItemName) {
// 默认0普通文件
let showResult = 0;
if (fileTypeResolving.isImgByName(fileItemName)) {
showResult = 1;
} else if (fileTypeResolving.isVideoByName(fileItemName)) {
showResult = 2;
} else if (fileTypeResolving.isAudioByName(fileItemName)) {
showResult = 3;
} else if (fileTypeResolving.isDoc(fileItemName)) {
showResult = 4;
} else if (fileTypeResolving.isExcel(fileItemName)) {
showResult = 5;
} else if (fileTypeResolving.isPPT(fileItemName)) {
showResult = 6;
} else if (fileTypeResolving.isPdf(fileItemName)) {
showResult = 7;
} else if (fileTypeResolving.isZip(fileItemName)) {
showResult = 8;
} else if (fileTypeResolving.isWeb(fileItemName)) {
showResult = 9;
} else if (fileTypeResolving.isTxt(fileItemName)) {
showResult = 10;
} else if (fileTypeResolving.isPsd(fileItemName)) {
showResult = 11;
} else if (fileTypeResolving.isCad(fileItemName)) {
showResult = 12;
} else if (fileTypeResolving.isIso(fileItemName)) {
showResult = 13;
} else if (fileTypeResolving.isExe(fileItemName)) {
showResult = 14;
}
return showResult
},
/**
* 获取文件显示图标
* @param filePath
* @returns {string}
*/
getFileItemShowIcon(filePath) {
let showIcon = '';
switch (this.resolvingShowByFileName(filePath)) {
case 0:
showIcon = "#icon-yunpanlogo-3";
break;
// 图片
case 1:
showIcon = this.getImgShowIcon(filePath);
break;
// 视频
case 2:
showIcon = "#icon-yunpanlogo-6";
break;
// 音乐
case 3:
showIcon = "#icon-yunpanlogo-4";
break;
// doc
case 4:
showIcon = "#icon-yunpanlogo-2";
break;
// excel
case 5:
showIcon = "#icon-yunpanlogo-";
break;
// ppt
case 6:
showIcon = "#icon-yunpanlogo-1";
break;
// pdf
case 7:
showIcon = "#icon-yunpanlogo-12";
break;
// zip
case 8:
showIcon = "#icon-yasuobao";
break;
// web文件
case 9:
showIcon = "#icon-yunpanlogo-5";
break;
// txt文件
case 10:
showIcon = "#icon-yunpanlogo-7";
break;
// PSD
case 11:
showIcon = "#icon-yunpanlogo-10";
break;
// cad
case 12:
showIcon = "#icon-yunpanlogo-11";
break;
// ISO
case 13:
showIcon = "#icon-yunpanlogo-8";
break;
// 可执行
case 14:
showIcon = "#icon-yunpanlogo-9";
break;
// 普通文件
default:
showIcon = "#icon-yunpanlogo-3";
}
return showIcon;
},
/**
* 获取图片的显示图标
* @param fileItem
* @returns {string|*}
*/
getImgShowIcon(fileItem) {
return FILE_DOMAIN + fileItem;
},
change(fileList) {
this.$emit("update:files", fileList.map(v => v.data))
},
afterRead(file) {
file.status = 'uploading';
file.message = '上传中...';
let formData = new FormData();
formData.append("file", file.file, file.file.name);
$.ajax({
url: "/platform/Common/uploadFile",
type: "post",
data: formData,
processData: false,
contentType: false,
success: (res) => {
const {code, data} = res
if (code === 0) {
file.status = 'success';
file.data = data
this.change(this.fileList)
}
},
error: (err) => {
file.status = 'failed';
file.message = '上传失败';
}
});
},
doDelete(file) {
if (file.data) {
const {filename, filepath} = file.data
if (this.del) {
$.post(FILE_DELETE_ADDRESS, {filepath})
}
this.change(this.fileList)
}
},
clickPreview(file) {
const {filepath, id} = file.data
const show = this.resolvingShowByFileName(filepath)
if (show == 4 || show == 5 || show == 7) {
preview(filepath, id)
}
},
updateFileList(val) {
if (!val || !val.length) {
this.fileList = []
return
}
this.fileList = val.map(v => {
let url = ''
if (this.resolvingShowByFileName(v.filepath) == 1) {
url = FILE_DOMAIN + v.filepath
}
return {data: v, url, file: {name: v.filename}, status: 'success'}
})
},
},
created() {
this.updateFileList(this.files)
}
}
</script>
<style>
</style>
@@ -0,0 +1,47 @@
class SysDictData {
constructor(dict) {
this.dict = dict
}
async init(dictNames) {
const ps = [];
dictNames.forEach((name) => {
Vue.set(this.dict.type, name, null)
ps.push(
getDictOptions(name).then((res) => {
const dictValue = res.map(v => {
return {
text: v.name,
label: v.name,
value: v.code,
raw: v
}
})
this.dict.type[name] = Object.freeze(dictValue)
})
)
})
await Promise.all(ps)
}
}
window.dictData = {}
window.dictData.install = function (Vue) {
Vue.mixin({
data() {
if (this.$options.dicts instanceof Array && this.$options.dicts.length > 0) {
return {dict: {type: {}}};
} else {
return {}
}
},
created() {
if (this.$options.dicts instanceof Array && this.$options.dicts.length > 0) {
new SysDictData(this.dict).init(this.$options.dicts);
}
}
})
}
if (window.Vue) {
Vue.use(window.dictData)
}
@@ -0,0 +1,58 @@
/**
*Desc:
*Create by: jug
*Create time:2023/7/28/9:55
*/
<template>
<div>
<template v-for="(item, index) in options">
<template v-if="values.includes(item.value)">
<span
v-if="item.raw.listClass == 'default' || item.raw.listClass == ''"
:key="item.value"
:index="index"
:class="item.raw.cssClass"
>{{ item.label }}</span
>
<van-tag
v-else
:disable-transitions="true"
:key="item.value"
:index="index"
:type="item.raw.listClass == 'primary' ? '' : item.raw.listClass"
:class="item.raw.cssClass"
>
{{ item.label }}
</van-tag>
</template>
</template>
</div>
</template>
<script>
module.exports = {
name: "DictTag",
props: {
options: {
type: Array,
default: null,
},
value: [Number, String, Array],
},
computed: {
values() {
if (this.value !== null && typeof this.value !== 'undefined') {
return Array.isArray(this.value) ? this.value : [String(this.value)];
} else {
return [];
}
},
},
}
</script>
<style scoped>
.el-tag + .el-tag {
margin-left: 10px;
}
</style>
@@ -0,0 +1,230 @@
/**
*Desc:
*Create by: jug
*Create time:2024/1/24/16:40
*/
<template>
<div>
<div ref="editorDom"></div>
<input type="file" style="display: none;">
</div>
</template>
<script src="/assets/platform/plugins/jquery/jquery-1.11.1.min.js"></script>
<script>
const {$, BtnMenu, DropListMenu, PanelMenu, DropList, Panel, Tooltip} = wangEditor
class AlertMenu extends BtnMenu {
constructor(editor) {
const $elem = wangEditor.$(
`<div class="w-e-menu" data-title="上传word">
word
</div>`
)
super($elem, editor)
}
clickHandler() {
const _this = this
const inputFileElement = document.querySelector('#'+this.editor.textElemId).parentElement.parentElement.nextElementSibling
inputFileElement.click()
inputFileElement.addEventListener('change', function () {
const file = this.files[0];
const fileName = file.name
if (!fileName.toLowerCase().endsWith('.doc') && !fileName.toLowerCase().endsWith('.docx')) {
alert('请上传doc或者docx的文件')
_this.clearInputFile()
return
}
const formData = new FormData()
formData.append('file', file, file.name)
axios.post('/file_server/word2Html', formData, {}).then(response => {
console.log(response.data)
if (response.data.code === 0) {
_this.editor.txt.html(response.data.data)
} else {
alert(response.data.msg + ',上传word失败,请联系管理员!')
_this.clearInputFile()
}
}).catch(error => {
console.log(error)
_this.clearInputFile()
alert('上传word失败,请联系管理员!')
});
});
}
clearInputFile() {
const obj = document.getElementById('fileInput');
obj.outerHTML = obj.outerHTML
}
tryChangeActive() {
this.active()
}
}
wangEditor.registerMenu('alertMenuKey', AlertMenu)
module.exports = {
name: "textEditor",
props: {
// 定义值属性,用于接收父组件传递的值
value: {
type: String,
default: ''
},
height: {
type: Number,
default: 300
},
menus: {
type: Array,
default: () => {
return [
'head',//标题
'bold',//加粗
'fontSize',//字号
'fontName',//字体
'italic',//斜体
'underline',//下划线
'strikeThrough',//删除线
'indent',//缩进
'lineHeight',//行高
'foreColor',//文字颜色
'backColor',//背景颜色
//'link',//链接
'list',//序列
'todo',//待办
'justify',//对齐
'quote',//引用
// 'emoticon',//表情
'image',
//'video',
'table',
//'code',
'splitLine',//分割线
'undo',
'redo',
]
}
}
},
data() {
return {
editor: null
}
},
mounted() {
this.initEditor()
},
watch: {
value: {
handler: function (newValue) {
this.$nextTick(() => {
this.editor.txt.html(newValue);
// this.editor.config.focus = true
})
// const _this = this
// const waitUntilEditorNotNull = () => {
// if (_this.editor != null) {
// _this.editor.txt.html(newValue);
// } else {
// setTimeout(waitUntilEditorNotNull, 100); // 每隔100毫秒检查一次
// }
// }
// waitUntilEditorNotNull();
},
immediate: true
}
},
methods: {
initEditor() {
let _this = this
this.editor = new wangEditor(this.$refs.editorDom)
// this.editor.config.focus = false // 取消光标自动定位
//内容change回调
this.editor.config.onchange = function (newHtml) {
let content = _this.editor.txt.html()
let text = _this.editor.txt.text()
// 对于一键格式化后的内容,空内容可能会出现<p></br></p>标签,此处进行判断
// if (_this.isEmptyEditor()) {
// content = ''
// }
const newContent = content.replaceAll('<img', '<image');
_this.$emit('input', newContent)
_this.$emit('catchData', newContent, text)
}
//配置图片上传
this.editor.config.customUploadImg = function (resultFiles, insertImgFn) {
// resultFiles 是 input 中选中的文件列表
// insertImgFn 是获取图片 url 后,插入到编辑器的方法
Promise.all(_this.uploadFiles(resultFiles)).then(res => {
res.forEach(v => {
if (v.code === 0) {
insertImgFn(APP_DOMAIN + CREATE_PREVIEW_URL(v.data.filepath))
} else {
ELEMENT.message.warning('图片上传失败')
}
})
})
}
//粘贴过滤
this.editor.config.pasteFilterStyle = false
//高度
this.editor.config.height = this.height
//菜单
this.editor.config.menus = this.menus
this.editor.create()
},
isEmptyEditor() {
const children = this.editor.$textElem.children()
for (let i = 0; i < children.elems.length; i++) {
const node = children.elems[i]
if (node && node.nodeType === Node.TEXT_NODE && node.textContent.trim().length !== '') {
return false
}
if (node && node.nodeType === Node.ELEMENT_NODE && node.tagName.toLowerCase() === 'p' && node.innerText.trim() !== '') {
return false
}
}
return true
},
uploadFiles(resultFiles) {
return resultFiles.map(async file => {
const formData = new FormData()
formData.append('file', file, file.name)
formData.append("folderPath", "/wangEditorImg/")
return jQuery.ajax({
url: '/file_server/uploadFile',
type: 'post',
data: formData,
processData: false,
contentType: false
})
})
}
},
created() {
}
}
</script>
<style scoped>
</style>