@@ -11,6 +11,8 @@
<style>
html,
body,
+
#app {
height: 100%;
margin: 0px;
@@ -91,7 +91,12 @@ const queryUserByDepId = (params) => getAction("/sys/user/queryUserByDepId", par
const queryUserRoleMap = (params) => getAction("/sys/user/queryUserRoleMap", params);
// 重复校验
const duplicateCheck = (params) => getAction("/sys/duplicate/check", params);
+// 加载分类字典
+const loadCategoryData = (params)=>getAction("/sys/category/loadAllData",params);
+/*update_begin author:wuxianquan date:20190908 for:添加查询一级菜单和子菜单查询api */
+const getSystemMenuList = (params)=>getAction("/sys/permission/getSystemMenuList",params);
+const getSystemSubmenu = (params)=>getAction("/sys/permission/getSystemSubmenu",params);
export {
// imgView,
// doMian,
@@ -139,7 +144,10 @@ export {
duplicateCheck,
queryTreeListForRole,
getIndustryList,
- getIndustryTreeList
+ getIndustryTreeList,
+ loadCategoryData,
+ getSystemMenuList,
+ getSystemSubmenu
}
@@ -0,0 +1,73 @@
+import Vue from 'vue'
+import { ACCESS_TOKEN } from "@/store/mutation-types"
+import store from '@/store'
+/**
+ * 单点登录
+ */
+const init = (callback) => {
+ console.log("-------单点登录开始-------");
+ let token = Vue.ls.get(ACCESS_TOKEN);
+ let st = getUrlParam("ticket");
+ var sevice = "http://"+window.location.host+"/";
+ if(token){
+ loginSuccess(callback);
+ }else{
+ if(st){
+ validateSt(st,sevice,callback);
+ var serviceUrl = encodeURIComponent(sevice);
+ window.location.href = window._CONFIG['casPrefixUrl']+"/login?service="+serviceUrl;
+ }
+ console.log("-------单点登录结束-------");
+};
+const SSO = {
+ init: init
+function getUrlParam(paraName) {
+ var url = document.location.toString();
+ var arrObj = url.split("?");
+ if (arrObj.length > 1) {
+ var arrPara = arrObj[1].split("&");
+ var arr;
+ for (var i = 0; i < arrPara.length; i++) {
+ arr = arrPara[i].split("=");
+ if (arr != null && arr[0] == paraName) {
+ return arr[1];
+ return "";
+ else {
+}
+function validateSt(ticket,service,callback){
+ let params = {
+ ticket: ticket,
+ service:service
+ };
+ store.dispatch('ValidateLogin',params).then(res => {
+ //this.departConfirm(res)
+ if(res.success){
+ }).catch((err) => {
+ console.log(err);
+ //that.requestFailed(err);
+ });
+function loginSuccess (callback) {
+ callback();
+export default SSO;
@@ -0,0 +1,61 @@
+<template>
+ <div :style="{ padding: '0 0 32px 32px' }">
+ <h4 :style="{ marginBottom: '20px' }">{{ title }}</h4>
+ <v-chart
+ height="254"
+ :data="datasource"
+ :forceFit="true"
+ :padding="['auto', 'auto', '40', '50']">
+ <v-tooltip />
+ <v-axis />
+ <v-bar position="x*y"/>
+ </v-chart>
+ </div>
+</template>
+<script>
+ const data = []
+ for (let i = 0; i < 12; i += 1) {
+ data.push({
+ x: `${i + 1}月`,
+ y: Math.floor(Math.random() * 1000) + 200
+ })
+ const tooltip = [
+ 'x*y',
+ (x, y) => ({
+ name: x,
+ value: y
+ ]
+ const scale = [{
+ dataKey: 'x',
+ min: 2
+ }, {
+ dataKey: 'y',
+ title: '时间',
+ min: 1,
+ max: 22
+ }]
+ export default {
+ name: "Bar",
+ props: {
+ title: {
+ type: String,
+ default: ''
+ },
+ mounted(){
+ this.datasource = data
+ data () {
+ return {
+ datasource:[],
+ scale,
+ tooltip
+</script>
@@ -0,0 +1,240 @@
+ <a-tree-select
+ allowClear
+ labelInValue
+ style="width: 100%"
+ :disabled="disabled"
+ :dropdownStyle="{ maxHeight: '400px', overflow: 'auto' }"
+ :placeholder="placeholder"
+ :loadData="asyncLoadTreeData"
+ :value="treeValue"
+ :treeData="treeData"
+ :multiple="multiple"
+ @change="onChange">
+ </a-tree-select>
+ import { getAction } from '@/api/manage'
+ name: 'JCategorySelect',
+ value:{
+ required: false
+ placeholder:{
+ default: '请选择',
+ disabled:{
+ type:Boolean,
+ default:false,
+ required:false
+ condition:{
+ type:String,
+ default:'',
+ // 是否支持多选
+ multiple: {
+ type: Boolean,
+ default: false,
+ loadTriggleChange:{
+ pid:{
+ pcode:{
+ back:{
+ treeValue:"",
+ treeData:[],
+ url:"/sys/category/loadTreeData",
+ view:'/sys/category/loadDictItem/',
+ tableName:"",
+ text:"",
+ code:"",
+ watch: {
+ value () {
+ this.loadItemByCode()
+ pcode(){
+ this.loadRoot();
+ created(){
+ this.validateProp().then(()=>{
+ this.loadRoot()
+ methods: {
+ /**加载一级节点 */
+ loadRoot(){
+ let param = {
+ pid:this.pid,
+ pcode:this.pcode,
+ condition:this.condition
+ getAction(this.url,param).then(res=>{
+ if(res.success && res.result){
+ for(let i of res.result){
+ i.value = i.key
+ if(i.leaf==false){
+ i.isLeaf=false
+ }else if(i.leaf==true){
+ i.isLeaf=true
+ this.treeData = [...res.result]
+ console.log("树一级节点查询结果-else",res)
+ /** 数据回显*/
+ loadItemByCode(){
+ if(!this.value || this.value=="0"){
+ this.treeValue = []
+ getAction(this.view,{ids:this.value}).then(res=>{
+ console.log(124345)
+ console.log(124345,res)
+ let values = this.value.split(',')
+ this.treeValue = res.result.map((item, index) => ({
+ key: values[index],
+ value: values[index],
+ label: item
+ }))
+ this.onLoadTriggleChange(res.result[0]);
+ onLoadTriggleChange(text){
+ //只有单选才会触发
+ if(!this.multiple && this.loadTriggleChange){
+ this.backValue(this.value,text)
+ backValue(value,label){
+ let obj = {}
+ if(this.back){
+ obj[this.back] = label
+ this.$emit('change', value, obj)
+ asyncLoadTreeData (treeNode) {
+ return new Promise((resolve) => {
+ if (treeNode.$vnode.children) {
+ resolve()
+ return
+ let pid = treeNode.$vnode.key
+ pid:pid,
+ this.addChildren(pid,res.result,this.treeData)
+ this.treeData = [...this.treeData]
+ addChildren(pid,children,treeArray){
+ if(treeArray && treeArray.length>0){
+ for(let item of treeArray){
+ if(item.key == pid){
+ if(!children || children.length==0){
+ item.isLeaf=true
+ item.children = children
+ break
+ this.addChildren(pid,children,item.children)
+ onChange(value){
+ if(!value){
+ this.$emit('change', '');
+ this.treeValue = ''
+ } else if (value instanceof Array) {
+ //this.$emit('change', value.map(item => item.value).join(','))
+ //this.treeValue = value
+ } else {
+ this.backValue(value.value,value.label)
+ this.treeValue = value
+ getCurrTreeData(){
+ return this.treeData
+ validateProp(){
+ let mycondition = this.condition
+ return new Promise((resolve,reject)=>{
+ if(!mycondition){
+ resolve();
+ try {
+ let test=JSON.parse(mycondition);
+ if(typeof test == 'object' && test){
+ this.$message.error("组件JTreeSelect-condition传值有误,需要一个json字符串!")
+ reject()
+ } catch(e) {
+ //2.2新增 在组件内定义 指定父组件调用时候的传值属性和事件类型 这个牛逼
+ model: {
+ prop: 'value',
+ event: 'change'
@@ -0,0 +1,65 @@
+ <div class="components-input-demo-presuffix">
+ <a-input @click="openModal" placeholder="corn表达式" v-model="cron" @change="handleOK">
+ <a-icon slot="prefix" type="schedule" title="corn控件"/>
+ <a-icon v-if="cron" slot="suffix" type="close-circle" @click="handleEmpty" title="清空"/>
+ </a-input>
+ <JCronModal ref="innerVueCron" :data="cron" @ok="handleOK"></JCronModal>
+ import JCronModal from "./modal/JCronModal";
+ name: 'JCron',
+ components: {
+ JCronModal
+ value: {
+ required: false,
+ data(){
+ cron: this.value,
+ watch:{
+ value(val){
+ this.cron = val
+ methods:{
+ openModal(){
+ this.$refs.innerVueCron.show();
+ handleOK(val){
+ this.cron = val;
+ this.$emit("change", this.cron);
+ //this.$emit("change", Object.assign({}, this.cron));
+ handleEmpty(){
+ this.handleOK('')
+<style scoped>
+ .components-input-demo-presuffix .anticon-close-circle {
+ cursor: pointer;
+ color: #ccc;
+ transition: color 0.3s;
+ font-size: 12px;
+ .components-input-demo-presuffix .anticon-close-circle:hover {
+ color: #f5222d;
+ .components-input-demo-presuffix .anticon-close-circle:active {
+ color: #666;
+</style>
@@ -0,0 +1,95 @@
+ <a-input :placeholder="placeholder" :value="inputVal" @input="backValue"></a-input>
+ const JINPUT_QUERY_LIKE = 'like';
+ const JINPUT_QUERY_NE = 'ne';
+ const JINPUT_QUERY_GE = 'ge'; //大于等于
+ const JINPUT_QUERY_LE = 'le'; //小于等于
+ name: 'JInput',
+ props:{
+ type:{
+ required:false,
+ default:JINPUT_QUERY_LIKE
+ default:''
+ immediate:true,
+ handler:function(){
+ this.initVal();
+ inputVal:''
+ initVal(){
+ if(!this.value){
+ this.inputVal = ''
+ let text = this.value
+ switch (this.type) {
+ case JINPUT_QUERY_LIKE:
+ text = text.substring(1,text.length-1);
+ break;
+ case JINPUT_QUERY_NE:
+ text = text.substring(1);
+ case JINPUT_QUERY_GE:
+ text = text.substring(2);
+ case JINPUT_QUERY_LE:
+ default:
+ this.inputVal = text
+ backValue(e){
+ let text = e.target.value
+ text = "*"+text+"*";
+ text = "!"+text;
+ text = ">="+text;
+ text = "<="+text;
+ this.$emit("change",text)
@@ -0,0 +1,928 @@
+ <a-modal
+ title="corn表达式"
+ :width="modalWidth"
+ :visible="visible"
+ :confirmLoading="confirmLoading"
+ @ok="handleSubmit"
+ @cancel="close"
+ cancelText="关闭">
+ <div class="card-container">
+ <a-tabs type="card">
+ <a-tab-pane key="1" type="card">
+ <span slot="tab"><a-icon type="schedule" /> 秒</span>
+ <a-radio-group v-model="result.second.cronEvery">
+ <a-row>
+ <a-radio value="1">每一秒钟</a-radio>
+ </a-row>
+ <a-radio value="2">每隔
+ <a-input-number size="small" v-model="result.second.incrementIncrement" :min="1" :max="59"></a-input-number>
+ 秒执行 从
+ <a-input-number size="small" v-model="result.second.incrementStart" :min="0" :max="59"></a-input-number>
+ 秒开始
+ </a-radio>
+ <a-radio value="3">具体秒数(可多选)</a-radio>
+ <a-select style="width:354px;" size="small" mode="multiple" v-model="result.second.specificSpecific">
+ <a-select-option v-for="(val,index) in 60" :key="index" :value="index">{{ index }}</a-select-option>
+ </a-select>
+ <a-radio value="4">周期从
+ <a-input-number size="small" v-model="result.second.rangeStart" :min="1" :max="59"></a-input-number>
+ 到
+ <a-input-number size="small" v-model="result.second.rangeEnd" :min="0" :max="59"></a-input-number>
+ 秒
+ </a-radio-group>
+ </a-tab-pane>
+ <a-tab-pane key="2">
+ <span slot="tab"><a-icon type="schedule" />分</span>
+ <div class="tabBody">
+ <a-radio-group v-model="result.minute.cronEvery">
+ <a-radio value="1">每一分钟</a-radio>
+ <a-input-number size="small" v-model="result.minute.incrementIncrement" :min="1" :max="60"></a-input-number>
+ 分执行 从
+ <a-input-number size="small" v-model="result.minute.incrementStart" :min="0" :max="59"></a-input-number>
+ 分开始
+ <a-radio value="3">具体分钟数(可多选)</a-radio>
+ <a-select style="width:340px;" size="small" mode="multiple" v-model="result.minute.specificSpecific">
+ <a-select-option v-for="(val,index) in Array(60)" :key="index" :value="index"> {{ index }}</a-select-option>
+ <a-input-number size="small" v-model="result.minute.rangeStart" :min="1" :max="60"></a-input-number>
+ <a-input-number size="small" v-model="result.minute.rangeEnd" :min="0" :max="59"></a-input-number>
+ 分
+ <a-tab-pane key="3">
+ <span slot="tab"><a-icon type="schedule" /> 时</span>
+ <a-radio-group v-model="result.hour.cronEvery">
+ <a-radio value="1">每一小时</a-radio>
+ <a-input-number size="small" v-model="result.hour.incrementIncrement" :min="0" :max="23"></a-input-number>
+ 小时执行 从
+ <a-input-number size="small" v-model="result.hour.incrementStart" :min="0" :max="23"></a-input-number>
+ 小时开始
+ <a-radio class="long" value="3">具体小时数(可多选)</a-radio>
+ <a-select style="width:340px;" size="small" mode="multiple" v-model="result.hour.specificSpecific">
+ <a-select-option v-for="(val,index) in Array(24)" :key="index" >{{ index }}</a-select-option>
+ <a-input-number size="small" v-model="result.hour.rangeStart" :min="0" :max="23"></a-input-number>
+ <a-input-number size="small" v-model="result.hour.rangeEnd" :min="0" :max="23"></a-input-number>
+ 小时
+ <a-tab-pane key="4">
+ <span slot="tab"><a-icon type="schedule" /> 天</span>
+ <a-radio-group v-model="result.day.cronEvery">
+ <a-radio value="1">每一天</a-radio>
+ <a-input-number size="small" v-model="result.week.incrementIncrement" :min="1" :max="7"></a-input-number>
+ 周执行 从
+ <a-select size="small" v-model="result.week.incrementStart">
+ <a-select-option v-for="(val,index) in Array(7)" :key="index" :value="index+1">{{ weekDays[index] }}</a-select-option>
+ 开始
+ <a-radio value="3">每隔
+ <a-input-number size="small" v-model="result.day.incrementIncrement" :min="1" :max="31"></a-input-number>
+ 天执行 从
+ <a-input-number size="small" v-model="result.day.incrementStart" :min="1" :max="31"></a-input-number>
+ 天开始
+ <a-radio class="long" value="4">具体星期几(可多选)</a-radio>
+ <a-select style="width:340px;" size="small" mode="multiple" v-model="result.week.specificSpecific">
+ <a-radio class="long" value="5">具体天数(可多选)</a-radio>
+ <a-select style="width:354px;" size="small" mode="multiple" v-model="result.day.specificSpecific">
+ <a-select-option v-for="(val,index) in Array(31)" :key="index" :value="index+1">{{ index+1 }}</a-select-option>
+ <a-radio value="6">在这个月的最后一天</a-radio>
+ <a-radio value="7">在这个月的最后一个工作日</a-radio>
+ <a-radio value="8">在这个月的最后一个
+ <a-select size="small" v-model="result.day.cronLastSpecificDomDay">
+ <a-radio value="9">
+ 在本月底前
+ <a-input-number size="small" v-model="result.day.cronDaysBeforeEomMinus" :min="1" :max="31"></a-input-number>
+ 天
+ <a-radio value="10">最近的工作日(周一至周五)至本月
+ <a-input-number size="small" v-model="result.day.cronDaysNearestWeekday" :min="1" :max="31"></a-input-number>
+ 日
+ <a-radio value="11">在这个月的第
+ <a-input-number size="small" v-model="result.week.cronNthDayNth" :min="1" :max="5"></a-input-number>
+ 个
+ <a-select size="small" v-model="result.week.cronNthDayDay">
+ <a-tab-pane key="5">
+ <span slot="tab"><a-icon type="schedule" /> 月</span>
+ <a-radio-group v-model="result.month.cronEvery">
+ <a-radio value="1">每一月</a-radio>
+ <a-input-number size="small" v-model="result.month.incrementIncrement" :min="0" :max="12"></a-input-number>
+ 月执行 从
+ <a-input-number size="small" v-model="result.month.incrementStart" :min="0" :max="12"></a-input-number>
+ 月开始
+ <a-radio class="long" value="3">具体月数(可多选)</a-radio>
+ <a-select style="width:354px;" size="small" filterable mode="multiple" v-model="result.month.specificSpecific">
+ <a-select-option v-for="(val,index) in Array(12)" :key="index" :value="index+1">{{ index+1 }}</a-select-option>
+ <a-radio value="4">从
+ <a-input-number size="small" v-model="result.month.rangeStart" :min="1" :max="12"></a-input-number>
+ <a-input-number size="small" v-model="result.month.rangeEnd" :min="1" :max="12"></a-input-number>
+ 月之间的每个月
+ <a-tab-pane key="6">
+ <span slot="tab"><a-icon type="schedule" /> 年</span>
+ <a-radio-group v-model="result.year.cronEvery">
+ <a-radio value="1">每一年</a-radio>
+ <a-input-number size="small" v-model="result.year.incrementIncrement" :min="1" :max="99"></a-input-number>
+ 年执行 从
+ <a-input-number size="small" v-model="result.year.incrementStart" :min="2019" :max="2119"></a-input-number>
+ 年开始
+ <a-radio class="long" value="3">具体年份(可多选)</a-radio>
+ <a-select style="width:354px;" size="small" filterable mode="multiple" v-model="result.year.specificSpecific">
+ <a-select-option v-for="(val,index) in Array(100)" :key="index" :value="2019+index">{{ 2019+index }}</a-select-option>
+ <a-input-number size="small" v-model="result.year.rangeStart" :min="2019" :max="2119"></a-input-number>
+ <a-input-number size="small" v-model="result.year.rangeEnd" :min="2019" :max="2119"></a-input-number>
+ 年之间的每一年
+ </a-tabs>
+ <div class="bottom">
+ <span class="value">{{this.cron }}</span>
+ </a-modal>
+ name:'VueCron',
+ props:['data'],
+ visible: false,
+ confirmLoading:false,
+ size:'large',
+ weekDays:['天','一','二','三','四','五','六'].map(val=>'星期'+val),
+ result: {
+ second:{},
+ minute:{},
+ hour:{},
+ day:{},
+ week:{},
+ month:{},
+ year:{}
+ defaultValue: {
+ second:{
+ cronEvery:'',
+ incrementStart:3,
+ incrementIncrement:5,
+ rangeStart:1,
+ rangeEnd:0,
+ specificSpecific:[],
+ minute:{
+ rangeEnd:'0',
+ hour:{
+ rangeStart:'0',
+ day:{
+ incrementStart:1,
+ incrementIncrement:'1',
+ rangeStart:'',
+ rangeEnd:'',
+ cronLastSpecificDomDay:1,
+ cronDaysBeforeEomMinus:1,
+ cronDaysNearestWeekday:1,
+ week:{
+ incrementIncrement:1,
+ cronNthDayDay:1,
+ cronNthDayNth:1,
+ month:{
+ rangeEnd:1,
+ year:{
+ incrementStart:2017,
+ rangeStart:2019,
+ rangeEnd: 2019,
+ label:''
+ computed: {
+ modalWidth(){
+ return 608;
+ secondsText() {
+ let seconds = '';
+ let cronEvery=this.result.second.cronEvery||'';
+ switch (cronEvery.toString()){
+ case '1':
+ seconds = '*';
+ case '2':
+ seconds = this.result.second.incrementStart+'/'+this.result.second.incrementIncrement;
+ case '3':
+ this.result.second.specificSpecific.map(val=> {seconds += val+','});
+ seconds = seconds.slice(0, -1);
+ case '4':
+ seconds = this.result.second.rangeStart+'-'+this.result.second.rangeEnd;
+ return seconds;
+ minutesText() {
+ let minutes = '';
+ let cronEvery=this.result.minute.cronEvery||'';
+ minutes = '*';
+ minutes = this.result.minute.incrementStart+'/'+this.result.minute.incrementIncrement;
+ this.result.minute.specificSpecific.map(val=> {
+ minutes += val+','
+ minutes = minutes.slice(0, -1);
+ minutes = this.result.minute.rangeStart+'-'+this.result.minute.rangeEnd;
+ return minutes;
+ hoursText() {
+ let hours = '';
+ let cronEvery=this.result.hour.cronEvery||'';
+ hours = '*';
+ hours = this.result.hour.incrementStart+'/'+this.result.hour.incrementIncrement;
+ this.result.hour.specificSpecific.map(val=> {
+ hours += val+','
+ hours = hours.slice(0, -1);
+ hours = this.result.hour.rangeStart+'-'+this.result.hour.rangeEnd;
+ return hours;
+ daysText() {
+ let days='';
+ let cronEvery=this.result.day.cronEvery||'';
+ case '11':
+ days = '?';
+ days = this.result.day.incrementStart+'/'+this.result.day.incrementIncrement;
+ case '5':
+ this.result.day.specificSpecific.map(val=> {
+ days += val+','
+ days = days.slice(0, -1);
+ case '6':
+ days = "L";
+ case '7':
+ days = "LW";
+ case '8':
+ days = this.result.day.cronLastSpecificDomDay + 'L';
+ case '9':
+ days = 'L-' + this.result.day.cronDaysBeforeEomMinus;
+ case '10':
+ days = this.result.day.cronDaysNearestWeekday+"W";
+ return days;
+ weeksText() {
+ let weeks = '';
+ weeks = '?';
+ weeks = this.result.week.incrementStart+'/'+this.result.week.incrementIncrement;
+ this.result.week.specificSpecific.map(val=> {
+ weeks += val+','
+ weeks = weeks.slice(0, -1);
+ weeks = "?";
+ weeks = this.result.week.cronNthDayDay+"#"+this.result.week.cronNthDayNth;
+ return weeks;
+ monthsText() {
+ let months = '';
+ let cronEvery=this.result.month.cronEvery||'';
+ months = '*';
+ months = this.result.month.incrementStart+'/'+this.result.month.incrementIncrement;
+ this.result.month.specificSpecific.map(val=> {
+ months += val+','
+ months = months.slice(0, -1);
+ months = this.result.month.rangeStart+'-'+this.result.month.rangeEnd;
+ return months;
+ yearsText() {
+ let years = '';
+ let cronEvery=this.result.year.cronEvery||'';
+ years = '*';
+ years = this.result.year.incrementStart+'/'+this.result.year.incrementIncrement;
+ this.result.year.specificSpecific.map(val=> {
+ years += val+','
+ years = years.slice(0, -1);
+ years = this.result.year.rangeStart+'-'+this.result.year.rangeEnd;
+ return years;
+ cron(){
+ return `${this.secondsText||'*'} ${this.minutesText||'*'} ${this.hoursText||'*'} ${this.daysText||'*'} ${this.monthsText||'*'} ${this.weeksText||'?'} ${this.yearsText||'*'}`
+ visible:{
+ handler() {
+ // if(this.data){
+ // //this. result = Object.keys(this.data.value).length>0?this.deepCopy(this.data.value):this.deepCopy(this.defaultValue);
+ // //this.result = Object.keys(this.data.value).length>0?clone(this.data.value):clone(this.defaultValue);
+ // //this.result = Object.keys(this.data.value).length>0?clone(JSON.parse(this.data.value)):clone(this.defaultValue);
+ // this.result = Object.keys(this.data.value).length>0?JSON.parse(this.data.value):JSON.parse(JSON.stringify(this.defaultValue));
+ // }else{
+ // //this.result = this.deepCopy(this.defaultValue);
+ // //this.result = clone(this.defaultValue);
+ // this.result = JSON.parse(JSON.stringify(this.defaultValue));
+ // }
+ let label = this.data;
+ if(label){
+ this.secondsReverseExp(label)
+ this.minutesReverseExp(label);
+ this.hoursReverseExp(label);
+ this.daysReverseExp(label);
+ this.monthsReverseExp(label);
+ this.yearReverseExp(label);
+ JSON.parse(JSON.stringify(label));
+ }else {
+ this.result = JSON.parse(JSON.stringify(this.defaultValue));
+ show(){
+ this.visible = true;
+ // console.log('secondsReverseExp',this.secondsReverseExp(this.data));
+ // console.log('minutesReverseExp',this.minutesReverseExp(this.data));
+ // console.log('hoursReverseExp',this.hoursReverseExp(this.data));
+ // console.log('daysReverseExp',this.daysReverseExp(this.data));
+ // console.log('monthsReverseExp',this.monthsReverseExp(this.data));
+ // console.log('yearReverseExp',this.yearReverseExp(this.data));
+ handleSubmit(){
+ this.$emit('ok',this.cron);
+ this.close();
+ this.visible = false;
+ close(){
+ secondsReverseExp(seconds) {
+ let val = seconds.split(" ")[0];
+ //alert(val);
+ let second = {
+ specificSpecific:[]
+ switch (true) {
+ case val.includes('*'):
+ second.cronEvery = '1';
+ case val.includes('/'):
+ second.cronEvery = '2';
+ second.incrementStart = val.split('/')[0];
+ second.incrementIncrement = val.split('/')[1];
+ case val.includes(','):
+ second.cronEvery = '3';
+ second.specificSpecific = val.split(',').map(Number).sort();
+ case val.includes('-'):
+ second.cronEvery = '4';
+ second.rangeStart = val.split('-')[0];
+ second.rangeEnd = val.split('-')[1];
+ this.result.second = second;
+ minutesReverseExp(minutes) {
+ let val = minutes.split(" ")[1];
+ let minute = {
+ minute.cronEvery = '1';
+ minute.cronEvery = '2';
+ minute.incrementStart = val.split('/')[0];
+ minute.incrementIncrement = val.split('/')[1];
+ minute.cronEvery = '3';
+ minute.specificSpecific = val.split(',').map(Number).sort();
+ minute.cronEvery = '4';
+ minute.rangeStart = val.split('-')[0];
+ minute.rangeEnd = val.split('-')[1];
+ this.result.minute = minute;
+ hoursReverseExp(hours) {
+ let val = hours.split(" ")[2];
+ let hour ={
+ hour.cronEvery = '1';
+ hour.cronEvery = '2';
+ hour.incrementStart = val.split('/')[0];
+ hour.incrementIncrement = val.split('/')[1];
+ hour.cronEvery = '3';
+ hour.specificSpecific = val.split(',').map(Number).sort();
+ hour.cronEvery = '4';
+ hour.rangeStart = val.split('-')[0];
+ hour.rangeEnd = val.split('-')[1];
+ this.result.hour = hour;
+ daysReverseExp(cron) {
+ let days = cron.split(" ")[3];
+ let weeks = cron.split(" ")[5];
+ let day ={
+ let week = {
+ cronNthDayNth:'1',
+ if (!days.includes('?')) {
+ case days.includes('*'):
+ day.cronEvery = '1';
+ case days.includes('?'):
+ // 2、4、11
+ case days.includes('/'):
+ day.cronEvery = '3';
+ day.incrementStart = days.split('/')[0];
+ day.incrementIncrement = days.split('/')[1];
+ case days.includes(','):
+ day.cronEvery = '5';
+ day.specificSpecific = days.split(',').map(Number).sort();
+ // day.specificSpecific.forEach(function (value, index) {
+ // day.specificSpecific[index] = value -1;
+ // });
+ case days.includes('LW'):
+ day.cronEvery = '7';
+ case days.includes('L-'):
+ day.cronEvery = '9';
+ day.cronDaysBeforeEomMinus = days.split('L-')[1];
+ case days.includes('L'):
+ //alert(days);
+ if(days.len == 1){
+ day.cronEvery = '6';
+ day.cronLastSpecificDomDay = '1';
+ else
+ {
+ day.cronEvery = '8';
+ day.cronLastSpecificDomDay = Number(days.split('L')[0]);
+ case days.includes('W'):
+ day.cronEvery = '10';
+ day.cronDaysNearestWeekday = days.split('W')[0];
+ switch (true){
+ case weeks.includes('/'):
+ day.cronEvery = '2';
+ week.incrementStart = weeks.split("/")[0];
+ week.incrementIncrement = weeks.split("/")[1];
+ case weeks.includes(','):
+ day.cronEvery = '4';
+ week.specificSpecific = weeks.split(',').map(Number).sort();
+ case '#':
+ day.cronEvery = '11';
+ week.cronNthDayDay = weeks.split("#")[0];
+ week.cronNthDayNth = weeks.split("#")[1];
+ week.cronEvery = '1';
+ this.result.day = day;
+ this.result.week = week;
+ monthsReverseExp(cron) {
+ let months = cron.split(" ")[4];
+ let month = {
+ case months.includes('*'):
+ month.cronEvery = '1';
+ case months.includes('/'):
+ month.cronEvery = '2';
+ month.incrementStart = months.split('/')[0];
+ month.incrementIncrement = months.split('/')[1];
+ case months.includes(','):
+ month.cronEvery = '3';
+ month.specificSpecific = months.split(',').map(Number).sort();
+ case months.includes('-'):
+ month.cronEvery = '4';
+ month.rangeStart = months.split('-')[0];
+ month.rangeEnd = months.split('-')[1];
+ this.result.month = month;
+ yearReverseExp(cron) {
+ let years = cron.split(" ")[6];
+ let year = {
+ rangeEnd:2019,
+ case years.includes('*'):
+ year.cronEvery = '1';
+ case years.includes('/'):
+ year.cronEvery = '2';
+ year.incrementStart = years.split('/')[0];
+ year.incrementIncrement = years.split('/')[1];
+ case years.includes(','):
+ year.cronEvery = '3';
+ year.specificSpecific = years.split(',').map(Number).sort();
+ case years.includes('-'):
+ year.cronEvery = '4';
+ year.rangeStart = years.split('-')[0];
+ year.rangeEnd = years.split('-')[1];
+ this.result.year = year;
+<style lang="scss">
+ .card-container {
+ background: #fff;
+ overflow: hidden;
+ padding: 12px;
+ position: relative;
+ width: 100%;
+ .ant-tabs{
+ border:1px solid #e6ebf5;
+ padding: 0;
+ .ant-tabs-bar {
+ margin: 0;
+ outline: none;
+ border-bottom: none;
+ .ant-tabs-nav-container{
+ .ant-tabs-tab {
+ padding: 0 24px!important;
+ background-color: #f5f7fa!important;
+ margin-right: 0px!important;
+ border-radius: 0;
+ line-height: 38px;
+ border: 1px solid transparent!important;
+ border-bottom: 1px solid #e6ebf5!important;
+ .ant-tabs-tab-active.ant-tabs-tab{
+ color: #409eff;
+ background-color: #fff!important;
+ border-right:1px solid #e6ebf5!important;
+ border-left:1px solid #e6ebf5!important;
+ border-bottom:1px solid #fff!important;
+ font-weight: normal;
+ transition:none!important;
+ .ant-tabs-tabpane{
+ padding: 15px;
+ .ant-row{
+ margin: 10px 0;
+ .ant-select,.ant-input-number{
+ width: 100px;
+<style lang="scss" scoped>
+ .container-widthEn{
+ width: 755px;
+ .container-widthCn{
+ width: 608px;
+ .language{
+ text-align: center;
+ position: absolute;
+ right: 13px;
+ top: 13px;
+ border: 1px solid transparent;
+ height: 40px;
+ font-size: 16px;
+ z-index: 1;
+ background: #f5f7fa;
+ width: 47px;
+ border-bottom: 1px solid #e6ebf5;
+ .card-container{
+ .bottom{
+ display: flex;
+ justify-content: center;
+ padding: 10px 0 0 0;
+ .cronButton{
+ margin: 0 10px;
+ line-height: 40px;
+ .tabBody{
+ .a-row{
+ .long{
+ .a-select{
+ width:354px;
+ .a-input-number{
+ width: 110px;
@@ -0,0 +1,315 @@
+ centered
+ :title="name + '选择'"
+ :width="width"
+ @ok="handleOk"
+ <a-row :gutter="18">
+ <a-col :span="16">
+ <!-- 查询区域 -->
+ <div class="table-page-search-wrapper">
+ <a-form layout="inline">
+ <a-row :gutter="24">
+ <a-col :span="14">
+ <a-form-item :label="(queryParamText||name)">
+ <a-input v-model="queryParam[queryParamCode||valueKey]" :placeholder="'请输入' + (queryParamText||name)" @pressEnter="searchQuery"/>
+ </a-form-item>
+ </a-col>
+ <a-col :span="8">
+ <span style="float: left;overflow: hidden;" class="table-page-search-submitButtons">
+ <a-button type="primary" @click="searchQuery" icon="search">查询</a-button>
+ <a-button type="primary" @click="searchReset" icon="reload" style="margin-left: 8px">重置</a-button>
+ </span>
+ </a-form>
+ <a-table
+ size="small"
+ bordered
+ :rowKey="rowKey"
+ :columns="innerColumns"
+ :dataSource="dataSource"
+ :pagination="ipagination"
+ :loading="loading"
+ :scroll="{ y: 240 }"
+ :rowSelection="{selectedRowKeys, onChange: onSelectChange, type: multiple ? 'checkbox':'radio'}"
+ :customRow="customRowFn"
+ @change="handleTableChange">
+ </a-table>
+ <a-card :title="'已选' + name" :bordered="false" :head-style="{padding:0}" :body-style="{padding:0}">
+ <a-table size="small" :rowKey="rowKey" bordered v-bind="selectedTable">
+ <span slot="action" slot-scope="text, record, index">
+ <a @click="handleDeleteSelected(record, index)">删除</a>
+ </a-card>
+ import { JeecgListMixin } from '@/mixins/JeecgListMixin'
+ import { cloneObject, pushIfNotExist } from '@/utils/util'
+ name: 'JSelectBizComponentModal',
+ mixins: [JeecgListMixin],
+ type: Array,
+ default: () => []
+ visible: {
+ default: false
+ valueKey: {
+ required: true
+ default: true
+ width: {
+ type: Number,
+ default: 900
+ name: {
+ listUrl: {
+ required: true,
+ // 根据 value 获取显示文本的地址,例如存的是 username,可以通过该地址获取到 realname
+ valueUrl: {
+ displayKey: {
+ default: null
+ columns: {
+ // 查询条件Code
+ queryParamCode: {
+ // 查询条件文字
+ queryParamText: {
+ rowKey: {
+ default: 'id'
+ data() {
+ innerValue: [],
+ // 表头
+ innerColumns: this.columns,
+ // 已选择列表
+ selectedTable: {
+ pagination: false,
+ scroll: { y: 240 },
+ columns: [
+ ...this.columns[0],
+ width: this.columns[0].widthRight || this.columns[0].width,
+ { title: '操作', dataIndex: 'action', align: 'center', width: 60, scopedSlots: { customRender: 'action' }, }
+ ],
+ dataSource: [],
+ url: { list: this.listUrl },
+ /* 分页参数 */
+ ipagination: {
+ current: 1,
+ pageSize: 5,
+ pageSizeOptions: ['5', '10', '20', '30'],
+ showTotal: (total, range) => {
+ return range[0] + '-' + range[1] + ' 共' + total + '条'
+ showQuickJumper: true,
+ showSizeChanger: true,
+ total: 0
+ options: [],
+ dataSourceMap: {},
+ deep: true,
+ immediate: true,
+ handler(val) {
+ this.innerValue = cloneObject(val)
+ this.selectedRowKeys = []
+ this.valueWatchHandler(val)
+ this.queryOptionsByValue(val)
+ dataSource: {
+ this.emitOptions(val)
+ this.valueWatchHandler(this.innerValue)
+ selectedRowKeys: {
+ this.selectedTable.dataSource = val.map(key => {
+ for (let data of this.dataSource) {
+ if (data[this.rowKey] === key) {
+ pushIfNotExist(this.innerValue, data[this.valueKey])
+ return data
+ for (let data of this.selectedTable.dataSource) {
+ console.warn('未找到选择的行信息,key:' + key)
+ return {}
+ /** 关闭弹窗 */
+ close() {
+ this.$emit('update:visible', false)
+ valueWatchHandler(val) {
+ val.forEach(item => {
+ this.dataSource.concat(this.selectedTable.dataSource).forEach(data => {
+ if (data[this.valueKey] === item) {
+ pushIfNotExist(this.selectedRowKeys, data[this.rowKey])
+ queryOptionsByValue(value) {
+ if (!value || value.length === 0) {
+ // 判断options是否存在value,如果已存在数据就不再请求后台了
+ let notExist = false
+ for (let val of value) {
+ let find = false
+ for (let option of this.options) {
+ if (val === option.value) {
+ find = true
+ if (!find) {
+ notExist = true
+ if (!notExist) return
+ getAction(this.valueUrl || this.listUrl, {
+ // 这里最后加一个 , 的原因是因为无论如何都要使用 in 查询,防止后台进行了模糊匹配,导致查询结果不准确
+ [this.valueKey]: value.join(',') + ',',
+ pageNo: 1,
+ pageSize: value.length
+ }).then((res) => {
+ if (res.success) {
+ let dataSource = res.result
+ if (!(dataSource instanceof Array)) {
+ dataSource = res.result.records
+ this.emitOptions(dataSource, (data) => {
+ pushIfNotExist(this.selectedTable.dataSource, data, this.rowKey)
+ emitOptions(dataSource, callback) {
+ dataSource.forEach(data => {
+ let key = data[this.valueKey]
+ this.dataSourceMap[key] = data
+ pushIfNotExist(this.options, { label: data[this.displayKey || this.valueKey], value: key }, 'value')
+ typeof callback === 'function' ? callback(data) : ''
+ this.$emit('options', this.options, this.dataSourceMap)
+ /** 完成选择 */
+ handleOk() {
+ let value = this.selectedTable.dataSource.map(data => data[this.valueKey])
+ this.$emit('input', value)
+ this.close()
+ /** 删除已选择的 */
+ handleDeleteSelected(record, index) {
+ this.selectedRowKeys.splice(this.selectedRowKeys.indexOf(record[this.rowKey]), 1)
+ this.selectedTable.dataSource.splice(index, 1)
+ customRowFn(record) {
+ on: {
+ click: () => {
+ let key = record[this.rowKey]
+ if (!this.multiple) {
+ this.selectedRowKeys = [key]
+ this.selectedTable.dataSource = [record]
+ let index = this.selectedRowKeys.indexOf(key)
+ if (index === -1) {
+ this.selectedRowKeys.push(key)
+ this.selectedTable.dataSource.push(record)
+ this.handleDeleteSelected(record, index)
+<style lang="less" scoped>
@@ -0,0 +1,36 @@
+# JSelectBizComponent
+Jeecg 选择组件的公共可复用组件
+## 引用方式
+```js
+import JSelectBizComponent from '@/src/components/jeecgbiz/JSelectBizComponent'
+export default {
+ components: { JSelectBizComponent }
+```
+## 参数
+### 配置参数
+| 参数名 | 类型 | 必填 | 默认值 | 备注 |
+|-----------------------|---------|------|--------------|--------------------------------------------------------------------------------------|
+| rowKey | String | | "id" | 唯一标识的字段名 |
+| value(v-model) | String | | "" | 默认选择的数据,多个用半角逗号分割 |
+| name | String | | "" | 显示名字,例如选择用户就填写"用户" |
+| listUrl | String | 是 | | 数据请求地址,必须是封装了分页的地址 |
+| valueUrl | String | | "" | 获取显示文本的地址,例如存的是 username,可以通过该地址获取到 realname |
+| displayKey | String | | null | 显示在标签上的字段 key ,不传则直接显示数据 |
+| returnKeys | Array | | ['id', 'id'] | v-model 绑定的 keys,是个数组,默认使用第二项,当配置了 `returnId=true` 就返回第一项 |
+| returnId | Boolean | | false | 返回ID,设为true后将返回配置的 `returnKeys` 中的第一项 |
+| selectButtonText | String | | "选择" | 选择按钮的文字 |
+| queryParamText | String | | null | 查询条件显示文字,不传则使用 `name` |
+| columns | Array | 是 | | 列配置项,与antd的table的配置完全一致。列的第一项会被配置成右侧已选择的列表上 |
+| columns[0].widthRight | Array | | null | 仅列的第一项可以应用此配置,表示右侧已选择列表的宽度,建议 `70%`,不传则应用`width` |
+| placeholder | String | | "请选择" | 占位符 |
+| disabled | Boolean | | false | 是否禁用 |
+| multiple | Boolean | | false | 是否可多选 |
+| buttons | Boolean | | true | 是否显示"选择"按钮,如果不显示,可以直接点击文本框打开选择界面 |
@@ -0,0 +1,158 @@
+ <a-row class="j-select-biz-component-box" type="flex" :gutter="8">
+ <a-col class="left" :class="{'full': !buttons}">
+ <slot name="left">
+ <a-select
+ mode="multiple"
+ v-model="selectValue"
+ :options="selectOptions"
+ :open="false"
+ style="width: 100%;"
+ @click.native="visible=(buttons?visible:true)"
+ />
+ </slot>
+ <a-col v-if="buttons" class="right">
+ <a-button type="primary" icon="search" :disabled="disabled" @click="visible=true">{{selectButtonText}}</a-button>
+ <j-select-biz-component-modal
+ :visible.sync="visible"
+ v-bind="modalProps"
+ @options="handleOptions"
+ import JSelectBizComponentModal from './JSelectBizComponentModal'
+ name: 'JSelectBizComponent',
+ components: { JSelectBizComponentModal },
+ /** 是否返回 id,默认 false,返回 code */
+ returnId: {
+ placeholder: {
+ default: '请选择'
+ disabled: {
+ // 是否支持多选,默认 true
+ // 是否显示按钮,默认 true
+ buttons: {
+ // 显示的 Key
+ // 返回的 key
+ returnKeys: {
+ default: () => ['id', 'id']
+ // 选择按钮文字
+ selectButtonText: {
+ default: '选择'
+ selectValue: [],
+ selectOptions: [],
+ visible: false
+ valueKey() {
+ return this.returnId ? this.returnKeys[0] : this.returnKeys[1]
+ modalProps() {
+ return Object.assign({
+ valueKey: this.valueKey,
+ multiple: this.multiple,
+ returnKeys: this.returnKeys,
+ displayKey: this.displayKey || this.valueKey
+ }, this.$attrs)
+ if (val) {
+ this.selectValue = val.split(',')
+ this.selectValue = []
+ selectValue: {
+ let rows = val.map(key => this.dataSourceMap[key])
+ this.$emit('select', rows)
+ let data = val.join(',')
+ this.$emit('input', data)
+ this.$emit('change', data)
+ handleOptions(options, dataSourceMap) {
+ this.selectOptions = options
+ this.dataSourceMap = dataSourceMap
+ .j-select-biz-component-box {
+ $width: 82px;
+ .left {
+ width: calc(100% - #{$width} - 8px);
+ .right {
+ width: #{$width};
+ .full {
+ /deep/ {
+ .ant-select-search__field {
+ display: none !important;
@@ -0,0 +1,37 @@
+ <j-select-biz-component :width="1000" v-bind="configs" v-on="$listeners"/>
+ import JSelectBizComponent from './JSelectBizComponent'
+ name: 'JSelectPosition',
+ components: { JSelectBizComponent },
+ props: ['value'],
+ settings: {
+ name: '职务',
+ displayKey: 'name',
+ returnKeys: ['id', 'code'],
+ listUrl: '/sys/position/list',
+ queryParamCode: 'name',
+ queryParamText: '职务名称',
+ { title: '职务名称', dataIndex: 'name', align: 'center', width: '30%', widthRight: '70%' },
+ { title: '职务编码', dataIndex: 'code', align: 'center', width: '35%' },
+ { title: '职级', dataIndex: 'rank_dictText', align: 'center', width: '25%' }
+ configs() {
+ return Object.assign({ value: this.value }, this.settings, this.$attrs)
+<style lang="scss" scoped></style>
@@ -0,0 +1,38 @@
+ <j-select-biz-component
+ :value="value"
+ name="角色"
+ displayKey="roleName"
+ :returnKeys="returnKeys"
+ :listUrl="url.list"
+ :columns="columns"
+ queryParamText="角色编码"
+ v-on="$listeners"
+ v-bind="$attrs"
+ name: 'JSelectMultiUser',
+ returnKeys: ['id', 'roleCode'],
+ url: { list: '/sys/role/list' },
+ { title: '角色名称', dataIndex: 'roleName', align: 'center', width: 120 },
+ { title: '角色编码', dataIndex: 'roleCode', align: 'center', width: 120 }
@@ -144,13 +144,13 @@ export const JeecgListMixin = {
if (this.superQueryParams) {
sqp['superQueryParams'] = encodeURI(this.superQueryParams)
+ if(this.queryParam.createTime){
+ this.queryParam.createTime = this.editDate(this.queryParam.createTime)
var param = Object.assign(sqp, this.queryParam, this.isorter, this.filters);
param.field = this.getQueryField();
param.pageNo = this.ipagination.current;
param.pageSize = this.ipagination.pageSize;
- if(param.createTime){
- param.createTime = this.editDate(param.createTime)
- }
return filterObj(param);
},
getQueryField() {
@@ -1,23 +1,23 @@
-export const JeecgListMixin = {
- data() {
- return {
- /* 分页参数 */
- ipagination: {
- current: 1,
- pageSize: 10,
- // pageSizeOptions: ['10', '20', '30'],
- showTotal: (total, range) => {
- return range[0] + "-" + range[1] + " 共" + total + "条"
- },
- showQuickJumper: true,
- // showSizeChanger: true,
- total: 0,
- onChange: current => {
- // 切换分页时的回调,
- // 当在页面定义change事件时,切记要把此处的事件清除,因为这两个事件重叠了,可能到时候会导致一些莫名的bug
- this.ipagination.current = current
+export const JeecgListMixin = {
+ pageSize: 10,
+ // pageSizeOptions: ['10', '20', '30'],
+ return range[0] + "-" + range[1] + " 共" + total + "条"
+ // showSizeChanger: true,
+ total: 0,
+ onChange: current => {
+ // 切换分页时的回调,
+ // 当在页面定义change事件时,切记要把此处的事件清除,因为这两个事件重叠了,可能到时候会导致一些莫名的bug
+ this.ipagination.current = current
@@ -2,14 +2,22 @@ import Vue from 'vue'
import Router from 'vue-router'
import {constantRouterMap} from '@/config/router.config'
+try {
+ const originalPush = Router.prototype.push
+ Router.prototype.push = function push(location) {
+ return originalPush.call(this, location).catch(err => err)
+ } catch (e) {
Vue.use(Router)
-const originalPush = Router.prototype.push;
-Router.prototype.push = function push(location) {
- if(location.name){
- return originalPush.call(this, location).catch(err => err)
-}
+// const originalPush = Router.prototype.push;
+// Router.prototype.push = function push(location) {
+// if(location.name){
+// return originalPush.call(this, location).catch(err => err)
+// }
export default new Router({
mode: 'history',
@@ -0,0 +1,107 @@
+ * LunarFullCalendar 公共 js
+ *
+ * @version 1.0.0
+ * @author sunjianlei
+ * */
+import { getRefPromise } from '@/utils/JEditableTableUtil'
+/* 日历的视图类型 */
+const calendarViewType = {
+ month: 'month', // 月视图
+ basicWeek: 'basicWeek', // 基础周视图
+ basicDay: 'basicDay',// 基础天视图
+ agendaWeek: 'agendaWeek', // 议程周视图
+ agendaDay: 'agendaDay', // 议程天视图
+/* 定义默认视图 */
+const defaultView = calendarViewType.month
+/* 定义日历默认配置 */
+const defaultSettings = {
+ locale: 'zh-cn',
+ // 按钮文字
+ buttonText: {
+ today: '今天',
+ month: '月',
+ week: '周',
+ day: '日'
+ // 头部排列方式
+ header: {
+ left: 'prev,next, today',
+ center: 'title',
+ right: 'hide, custom, month,agendaWeek,agendaDay'
+ //点击今天日列表图
+ eventLimitClick: 'day',
+ // 隐藏超出的事件
+ eventLimit: true,
+ // 设置每周开始日期为周日
+ firstDay: 0,
+ // 默认显示视图
+ defaultView,
+ timeFormat: 'H:mm',
+ axisFormat: 'H:mm',
+ // agenda视图下是否显示all-day
+ allDaySlot: true,
+ // agenda视图下all-day的显示文本
+ allDayText: '全天',
+ // 时区默认本地的
+ timezone: 'local',
+ // 周视图和日视同的左侧时间显示
+ slotLabelFormat: 'HH:mm',
+ // 设置第二天阈值
+ nextDayThreshold: '00:00:00',
+/** 提供了一些增强方法 */
+const CalendarMixins = {
+ calenderCurrentViewType: defaultView
+ getCalendarConfigEventHandler() {
+ // 处理 view changed 事件
+ viewRender: (view, element) => {
+ let { type } = view
+ let lastViewType = this.calenderCurrentViewType
+ this.calenderCurrentViewType = type
+ if (typeof this.handleViewRender === 'function') {
+ this.handleViewRender(type, view, element)
+ if (lastViewType !== this.calenderCurrentViewType && typeof this.handleViewChanged === 'function') {
+ this.handleViewChanged(type, view, element)
+ /** 获取 LunarFullCalendar 实例,ref = baseCalendar */
+ getCalendar(fn) {
+ return getRefPromise(this, 'baseCalendar').then(fn)
+ calendarEmit(name, data) {
+ this.getCalendar(ref => ref.$emit(name, data))
+ /** 强制重新加载所有的事件(日程)*/
+ calendarReloadEvents() {
+ this.calendarEmit('reload-events')
+export { defaultSettings, calendarViewType, CalendarMixins }
@@ -274,3 +274,43 @@ export const transformTozTreeFormat = (sNodes, setting={}) => {
return [sNodes];
+ * 如果值不存在就 push 进数组,反之不处理
+ * @param array 要操作的数据
+ * @param value 要添加的值
+ * @param key 可空,如果比较的是对象,可能存在地址不一样但值实际上是一样的情况,可以传此字段判断对象中唯一的字段,例如 id。不传则直接比较实际值
+ * @returns {boolean} 成功 push 返回 true,不处理返回 false
+export function pushIfNotExist(array, value, key) {
+ for (let item of array) {
+ if (key && (item[key] === value[key])) {
+ return false
+ } else if (item === value) {
+ array.push(value)
+ return true
+ /**
+ * 重复值验证工具方法
+ * 使用示例:
+ * { validator: (rule, value, callback) => validateDuplicateValue('sys_fill_rule', 'rule_code', value, this.model.id, callback) }
+ * @param tableName 被验证的表名
+ * @param fieldName 被验证的字段名
+ * @param fieldVal 被验证的值
+ * @param dataId 数据ID,可空
+ * @param callback
+export function validateDuplicateValue(tableName, fieldName, fieldVal, dataId, callback) {
+ let params = { tableName, fieldName, fieldVal, dataId }
+ api.duplicateCheck(params).then(res => {
+ res['success'] ? callback() : callback(res['message'])
+ }).catch(err => {
+ callback(err.message || err)
@@ -0,0 +1,519 @@
+ <div class="page-header-index-wide">
+ <a-col :sm="24" :md="12" :xl="6" :style="{ marginBottom: '24px' }">
+ <chart-card :loading="loading" title="受理量" :total="cardCount.sll | NumberFormat">
+ <a-tooltip title="指标说明" slot="action">
+ <a-icon type="info-circle-o" />
+ </a-tooltip>
+ <div>
+ <mini-area :datasource="chartData.sll" />
+ <template slot="footer">今日受理量:<span>{{ todaySll }}</span></template>
+ </chart-card>
+ <chart-card :loading="loading" title="办结量" :total="cardCount.bjl | NumberFormat">
+ <mini-area :datasource="chartData.bjl"/>
+ <template slot="footer">今日办结量:<span>{{ todayBjl }}</span></template>
+ <chart-card :loading="loading" title="用户受理量" :total="cardCount.isll | NumberFormat">
+ <mini-bar :datasource="chartData.isll" :height="50"/>
+ <template slot="footer">用户今日受理量:<span>{{ todayISll }}</span></template>
+ <chart-card :loading="loading" title="用户办结量" :total="cardCount.ibjl | NumberFormat">
+ <mini-bar :datasource="chartData.ibjl" :height="50"/>
+ <template slot="footer">用户今日办结量:<span>{{ todayIBjl }}</span></template>
+ <a-card :loading="loading" :bordered="false" :body-style="{padding: '0'}">
+ <div class="salesCard">
+ <a-tabs default-active-key="1" size="large" :tab-bar-style="{marginBottom: '24px', paddingLeft: '16px'}">
+ <div class="extra-wrapper" slot="tabBarExtraContent">
+ <div class="extra-item">
+ <a>今日</a>
+ <a>本周</a>
+ <a>本月</a>
+ <a>本年</a>
+ <a-range-picker :style="{width: '256px'}" />
+ <a-tab-pane loading="true" tab="受理监管" key="1">
+ <a-col :xl="16" :lg="12" :md="12" :sm="24" :xs="24">
+ <index-bar title="受理量统计" />
+ <a-col :xl="8" :lg="12" :md="12" :sm="24" :xs="24">
+ <a-card title="快速开始 / 便捷导航" style="margin-bottom: 24px" :bordered="false" :body-style="{padding: 0}">
+ <div class="item-group">
+ <a-col :class="'more-btn'" :span="12" v-for="(item,index) in registerTypeList" :key=" 'registerType'+index ">
+ <a-button @click="goPage(index)" style="margin-bottom:10px" size="small" type="primary" ghost>{{ item.text }}</a-button>
+ <a-tab-pane tab="交互监管" key="2">
+ <bar-multid :sourceData="jhjgData" :fields="jhjgFields" title="平台与部门交互量统计"></bar-multid>
+ <a-tab-pane tab="存储监管" key="4">
+ <template v-if="diskInfo && diskInfo.length>0">
+ <a-col :span="12" v-for="(item,index) in diskInfo" :key=" 'diskInfo'+index ">
+ <dash-chart-demo :title="item.name" :datasource="item.restPPT"></dash-chart-demo>
+ </template>
+ <a-col :class="'more-btn'" :span="10" v-for="(item,index) in registerTypeList" :key=" 'registerType'+index ">
+ <a-row :gutter="12">
+ <a-card :loading="loading" :class="{ 'anty-list-cust':true }" :bordered="false" :style="{ marginTop: '24px' }">
+ <a-tabs v-model="indexBottomTab" size="large" :tab-bar-style="{marginBottom: '24px', paddingLeft: '16px'}">
+ <a-radio-group v-model="indexRegisterType" @change="changeRegisterType">
+ <a-radio-button value="转移登记">转移登记</a-radio-button>
+ <a-radio-button value="抵押登记">抵押登记</a-radio-button>
+ <a-radio-button value="">所有</a-radio-button>
+ <a-tab-pane loading="true" tab="业务流程限时监管" key="1">
+ <a-table :dataSource="dataSource1" size="default" rowKey="id" :columns="columns" :pagination="ipagination1" @change="tableChange1">
+ <template slot="flowRate" slot-scope="text, record, index">
+ <a-progress :strokeColor="getPercentColor(record.flowRate)" :format="getPercentFormat" :percent="getFlowRateNumber(record.flowRate)" style="width:80px" />
+ <a-tab-pane loading="true" tab="业务节点限时监管" key="2">
+ <a-table :dataSource="dataSource2" size="default" rowKey="id" :columns="columns2" :pagination="ipagination2" @change="tableChange2">
+ <span style="color: red;">{{ record.flowRate }}小时</span>
+ import ACol from "ant-design-vue/es/grid/Col"
+ import ATooltip from "ant-design-vue/es/tooltip/Tooltip"
+ import ChartCard from '@/components/ChartCard'
+ import MiniBar from '@/components/chart/MiniBar'
+ import MiniArea from '@/components/chart/MiniArea'
+ import IndexBar from '@/components/chart/IndexBar'
+ import BarMultid from '@/components/chart/BarMultid'
+ import DashChartDemo from '@/components/chart/DashChartDemo'
+ const jhjgData = [
+ { type: '房管', '1月': 900, '2月': 1120, '3月': 1380, '4月': 1480, '5月': 1450, '6月': 1100, '7月':1300, '8月':900,'9月':1000 ,'10月':1200 ,'11月':600 ,'12月':900 },
+ { type: '税务', '1月':1200, '2月': 1500, '3月': 1980, '4月': 2000, '5月': 1000, '6月': 600, '7月':900, '8月':1100,'9月':1300 ,'10月':2000 ,'11月':900 ,'12月':1100 },
+ { type: '不动产', '1月':2000, '2月': 1430, '3月': 1300, '4月': 1400, '5月': 900, '6月': 500, '7月':600, '8月':1000,'9月':600 ,'10月':1000 ,'11月':1500 ,'12月':1200 }
+ const jhjgFields=[
+ '1月','2月','3月','4月','5月','6月',
+ '7月','8月','9月','10月','11月','12月'
+ const xljgData = [
+ {type:'一月',"房管":1.12,"税务":1.55,"不动产":1.2},
+ {type:'二月',"房管":1.65,"税务":1.32,"不动产":1.42},
+ {type:'三月',"房管":1.85,"税务":1.1,"不动产":1.5},
+ {type:'四月',"房管":1.33,"税务":1.63,"不动产":1.4},
+ {type:'五月',"房管":1.63,"税务":1.8,"不动产":1.7},
+ {type:'六月',"房管":1.85,"税务":1.98,"不动产":1.8},
+ {type:'七月',"房管":1.98,"税务":1.5,"不动产":1.76},
+ {type:'八月',"房管":1.48,"税务":1.2,"不动产":1.3},
+ {type:'九月',"房管":1.41,"税务":1.9,"不动产":1.6},
+ {type:'十月',"房管":1.1,"税务":1.1,"不动产":1.4},
+ {type:'十一月',"房管":1.85,"税务":1.6,"不动产":1.5},
+ {type:'十二月',"房管":1.5,"税务":1.4,"不动产":1.3}
+ const xljgFields=["房管","税务","不动产"]
+ const dataCol1 = [{
+ title: '业务号',
+ align:"center",
+ dataIndex: 'reBizCode'
+ },{
+ title: '业务类型',
+ dataIndex: 'type'
+ title: '受理人',
+ dataIndex: 'acceptBy'
+ title: '受理时间',
+ dataIndex: 'acceptDate'
+ title: '当前节点',
+ dataIndex: 'curNode'
+ title: '办理时长',
+ dataIndex: 'flowRate',
+ scopedSlots: { customRender: 'flowRate' }
+ }];
+ const dataSource1=[
+ {reBizCode:"1",type:"转移登记",acceptBy:'张三',acceptDate:"2019-01-22",curNode:"任务分派",flowRate:60},
+ {reBizCode:"2",type:"抵押登记",acceptBy:'李四',acceptDate:"2019-01-23",curNode:"领导审核",flowRate:30},
+ {reBizCode:"3",type:"转移登记",acceptBy:'王武',acceptDate:"2019-01-25",curNode:"任务处理",flowRate:20},
+ {reBizCode:"4",type:"转移登记",acceptBy:'赵楼',acceptDate:"2019-11-22",curNode:"部门审核",flowRate:80},
+ {reBizCode:"5",type:"转移登记",acceptBy:'钱就',acceptDate:"2019-12-12",curNode:"任务分派",flowRate:90},
+ {reBizCode:"6",type:"转移登记",acceptBy:'孙吧',acceptDate:"2019-03-06",curNode:"任务处理",flowRate:10},
+ {reBizCode:"7",type:"抵押登记",acceptBy:'周大',acceptDate:"2019-04-13",curNode:"任务分派",flowRate:100},
+ {reBizCode:"8",type:"抵押登记",acceptBy:'吴二',acceptDate:"2019-05-09",curNode:"任务上报",flowRate:50},
+ {reBizCode:"9",type:"抵押登记",acceptBy:'郑爽',acceptDate:"2019-07-12",curNode:"任务处理",flowRate:63},
+ {reBizCode:"20",type:"抵押登记",acceptBy:'林有',acceptDate:"2019-12-12",curNode:"任务打回",flowRate:59},
+ {reBizCode:"11",type:"转移登记",acceptBy:'码云',acceptDate:"2019-09-10",curNode:"任务签收",flowRate:87},
+ const dataCol2 = [{
+ title: '发起时间',
+ title: '超时时间',
+ const dataSource2=[
+ {reBizCode:"A001",type:"转移登记",acceptBy:'张四',acceptDate:"2019-01-22",curNode:"任务分派",flowRate:12},
+ {reBizCode:"A002",type:"抵押登记",acceptBy:'李吧',acceptDate:"2019-01-23",curNode:"任务签收",flowRate:3},
+ {reBizCode:"A003",type:"转移登记",acceptBy:'王三',acceptDate:"2019-01-25",curNode:"任务处理",flowRate:24},
+ {reBizCode:"A004",type:"转移登记",acceptBy:'赵二',acceptDate:"2019-11-22",curNode:"部门审核",flowRate:10},
+ {reBizCode:"A005",type:"转移登记",acceptBy:'钱大',acceptDate:"2019-12-12",curNode:"任务签收",flowRate:8},
+ {reBizCode:"A006",type:"转移登记",acceptBy:'孙就',acceptDate:"2019-03-06",curNode:"任务处理",flowRate:10},
+ {reBizCode:"A007",type:"抵押登记",acceptBy:'周晕',acceptDate:"2019-04-13",curNode:"部门审核",flowRate:24},
+ {reBizCode:"A008",type:"抵押登记",acceptBy:'吴有',acceptDate:"2019-05-09",curNode:"部门审核",flowRate:30},
+ {reBizCode:"A009",type:"抵押登记",acceptBy:'郑武',acceptDate:"2019-07-12",curNode:"任务分派",flowRate:1},
+ {reBizCode:"A0010",type:"抵押登记",acceptBy:'林爽',acceptDate:"2019-12-12",curNode:"部门审核",flowRate:16},
+ {reBizCode:"A0011",type:"转移登记",acceptBy:'码楼',acceptDate:"2019-09-10",curNode:"部门审核",flowRate:7},
+ name: "IndexBdc",
+ ATooltip,
+ ACol,
+ ChartCard,
+ MiniArea,
+ MiniBar,
+ DashChartDemo,
+ BarMultid,
+ IndexBar
+ loading: true,
+ cardCount:{
+ sll:100,
+ bjl:87,
+ isll:15,
+ ibjl:9
+ todaySll:60,
+ todayBjl:54,
+ todayISll:13,
+ todayIBjl:7,
+ chartData:{
+ sll:[],
+ bjl:[],
+ isll:[],
+ ibjl:[]
+ jhjgFields,
+ jhjgData,
+ xljgData,
+ xljgFields,
+ diskInfo:[
+ {name:"C盘",restPPT:7},
+ {name:"D盘",restPPT:5}
+ registerTypeList:[{
+ text:"业务受理"
+ text:"业务管理"
+ text:"文件管理"
+ text:"信息查询"
+ }],
+ dataSource1:[],
+ dataSource2:[],
+ columns:dataCol1,
+ columns2:dataCol2,
+ ipagination1:{
+ pageSizeOptions: ['10', '20', '30'],
+ ipagination2:{
+ indexRegisterType:"转移登记",
+ indexBottomTab:"1"
+ goPage(){
+ this.$message.success("根据业务自行处理跳转页面!")
+ changeRegisterType(e){
+ this.indexRegisterType = e.target.value
+ if(this.indexBottomTab=="1"){
+ this.loadDataSource1()
+ this.loadDataSource2()
+ tableChange1(pagination){
+ this.ipagination1.current = pagination.current
+ this.ipagination1.pageSize = pagination.pageSize
+ this.queryTimeoutInfo()
+ tableChange2(pagination){
+ this.ipagination2.current = pagination.current
+ this.ipagination2.pageSize = pagination.pageSize
+ this.queryNodeTimeoutInfo()
+ getFlowRateNumber(value){
+ return Number(value)
+ getPercentFormat(value){
+ if(value==100){
+ return "超时"
+ return value+"%"
+ getPercentColor(value){
+ let p = Number(value)
+ if(p>=90 && p<100){
+ return 'rgb(244, 240, 89)'
+ }else if(p>=100){
+ return 'red'
+ return 'rgb(16, 142, 233)'
+ loadDataSource1(){
+ this.dataSource1 = dataSource1.filter(item=>{
+ if(!this.indexRegisterType){
+ return item.type==this.indexRegisterType
+ loadDataSource2(){
+ this.dataSource2 = dataSource2.filter(item=>{
+ created() {
+ setTimeout(() => {
+ this.loading = !this.loading
+ }, 1000)
+ .extra-wrapper {
+ line-height: 55px;
+ padding-right: 24px;
+ .extra-item {
+ display: inline-block;
+ margin-right: 24px;
+ a {
+ margin-left: 24px;
+ .item-group {
+ padding: 20px 0 8px 24px;
+ font-size: 0;
+ color: rgba(0, 0, 0, 0.65);
+ font-size: 14px;
+ margin-bottom: 13px;
+ width: 25%;
+ .more-btn {
+ .list-content-item {
+ color: rgba(0, 0, 0, .45);
+ vertical-align: middle;
+ margin-left: 40px;
+ @media only screen and (min-width: 1600px) {
+ .list-content-item{
+ margin-left:60px;
+ @media only screen and (max-width: 1300px) {
+ margin-left:20px;
+ .width-hidden4{
+ display:none
+ span{line-height: 20px;}
+ p{margin-top: 4px;margin-bottom:0;line-height:22px;}
+ .anty-list-cust {
+ .ant-list-item-meta{flex: 0.3 !important;}
+ .ant-list-item-content{flex:1 !important; justify-content:flex-start !important;margin-left: 20px;}
@@ -0,0 +1,269 @@
+ <chart-card :loading="loading" title="总销售额" total="¥126,560">
+ <trend flag="up" style="margin-right: 16px;">
+ <span slot="term">周同比</span>
+ 12%
+ </trend>
+ <trend flag="down">
+ <span slot="term">日同比</span>
+ 11%
+ <template slot="footer">日均销售额<span>¥ 234.56</span></template>
+ <chart-card :loading="loading" title="访问量" :total="8846 | NumberFormat">
+ <mini-area />
+ <template slot="footer">日访问量<span> {{ '1234' | NumberFormat }}</span></template>
+ <chart-card :loading="loading" title="支付笔数" :total="6560 | NumberFormat">
+ <mini-bar :height="40" />
+ <template slot="footer">转化率 <span>60%</span></template>
+ <chart-card :loading="loading" title="运营活动效果" total="78%">
+ <mini-progress color="rgb(19, 194, 194)" :target="80" :percentage="78" :height="8" />
+ <template slot="footer">
+ <trend flag="down" style="margin-right: 16px;">
+ <span slot="term">同周比</span>
+ <trend flag="up">
+ <span slot="term">日环比</span>
+ 80%
+ <a-tab-pane loading="true" tab="销售额" key="1">
+ <bar title="销售额排行" :dataSource="barData"/>
+ <rank-list title="门店销售排行榜" :list="rankList"/>
+ <a-tab-pane tab="访问量" key="2">
+ <bar title="销售额趋势" :dataSource="barData"/>
+ <a-col :span="24">
+ <a-card :loading="loading" :bordered="false" title="最近一周访问次数统计" :style="{ marginTop: '24px' }">
+ <a-col :span="6">
+ <head-info title="今日访问IP数" :content="loginfo.todayIp"></head-info>
+ <a-col :span="2">
+ <a-spin class='circle-cust'>
+ <a-icon slot="indicator" type="environment" style="font-size: 24px" />
+ </a-spin>
+ <head-info title="今日访问次数" :content="loginfo.todayVisitCount"></head-info>
+ <a-icon slot="indicator" type="team" style="font-size: 24px" />
+ <head-info title="访问总次数" :content="loginfo.totalVisitCount"></head-info>
+ <a-icon slot="indicator" type="rise" style="font-size: 24px" />
+ <line-chart-multid :fields="visitFields" :dataSource="visitInfo"></line-chart-multid>
+ import MiniProgress from '@/components/chart/MiniProgress'
+ import RankList from '@/components/chart/RankList'
+ import Bar from '@/components/chart/Bar'
+ import LineChartMultid from '@/components/chart/LineChartMultid'
+ import HeadInfo from '@/components/tools/HeadInfo.vue'
+ import Trend from '@/components/Trend'
+ import { getLoginfo,getVisitInfo } from '@/api/api'
+ const rankList = []
+ for (let i = 0; i < 7; i++) {
+ rankList.push({
+ name: '白鹭岛 ' + (i+1) + ' 号店',
+ total: 1234.56 - i * 100
+ const barData = []
+ barData.push({
+ name: "IndexChart",
+ MiniProgress,
+ RankList,
+ Bar,
+ Trend,
+ LineChartMultid,
+ HeadInfo
+ center: null,
+ rankList,
+ barData,
+ loginfo:{},
+ visitFields:['ip','visit'],
+ visitInfo:[],
+ indicator: <a-icon type="loading" style="font-size: 24px" spin />
+ this.initLogInfo();
+ initLogInfo () {
+ getLoginfo(null).then((res)=>{
+ Object.keys(res.result).forEach(key=>{
+ res.result[key] =res.result[key]+""
+ this.loginfo = res.result;
+ getVisitInfo().then(res=>{
+ console.log("aaaaaa",res.result)
+ this.visitInfo = res.result;
+ .circle-cust{
+ top: 28px;
+ left: -100%;
+ /* 首页访问量统计 */
+ .head-info {
+ text-align: left;
+ padding: 0 32px 0 0;
+ min-width: 125px;
+ &.center {
+ padding: 0 32px;
+ span {
+ font-size: .95rem;
+ line-height: 42px;
+ margin-bottom: 4px;
+ p {
+ font-weight: 600;
+ font-size: 1rem;
@@ -0,0 +1,372 @@
+ <div class="index-container-ty">
+ <a-spin :spinning="loading">
+ <a-row type="flex" justify="start" :gutter="3">
+ <a-col :sm="24" :lg="12">
+ <a-card>
+ <div slot="title" class="index-md-title">
+ <img src="../../assets/daiban.png"/>
+ 我的待办【{{ dataSource1.length }}】
+ <div slot="extra">
+ <a v-if="dataSource1 && dataSource1.length>0" slot="footer" @click="goPage">更多 <a-icon type="double-right" /></a>
+ :class="'my-index-table tytable1'"
+ ref="table1"
+ rowKey="id"
+ :dataSource="dataSource1"
+ :pagination="false">
+ <template slot="ellipsisText" slot-scope="text">
+ <j-ellipsis :value="text" :length="textMaxLength"></j-ellipsis>
+ <template slot="dayWarnning" slot-scope="text,record">
+ <a-icon type="bulb" theme="twoTone" style="font-size:22px" :twoToneColor="getTipColor(record)"/>
+ <span slot="action" slot-scope="text, record">
+ <a @click="handleData">办理</a>
+ <img src="../../assets/zaiban.png"/>
+ 我的在办【{{ dataSource2.length }}】
+ <a v-if="dataSource2 && dataSource2.length>0" slot="footer" @click="goPage">更多 <a-icon type="double-right" /></a>
+ :class="'my-index-table tytable2'"
+ ref="table2"
+ :dataSource="dataSource2"
+ <div style="height: 5px;"></div>
+ <img src="../../assets/guaz.png"/>
+ 我的挂账【{{ dataSource4.length }}】
+ :class="'my-index-table tytable4'"
+ ref="table4"
+ :dataSource="dataSource4"
+ <img src="../../assets/duban.png"/>
+ 我的督办【{{ dataSource3.length }}】
+ :class="'my-index-table tytable3'"
+ ref="table3"
+ :dataSource="dataSource3"
+ import noDataPng from '@/assets/nodata.png'
+ import JEllipsis from '@/components/jeecg/JEllipsis'
+ const tempSs1=[{
+ id:"001",
+ orderNo:"电[1]1267102",
+ orderTitle:"药品出问题了",
+ restDay:1
+ id:"002",
+ orderNo:"电[4]5967102",
+ orderTitle:"吃了xxx医院的药,病情越来越严重",
+ restDay:0
+ id:"003",
+ orderNo:"电[3]5988987",
+ orderTitle:"今天去超市买鸡蛋,鸡蛋都是坏的",
+ restDay:7
+ id:"004",
+ orderNo:"电[2]5213491",
+ orderTitle:"xx宝实体店高价售卖xx",
+ restDay:5
+ id:"005",
+ orderNo:"电[1]1603491",
+ orderTitle:"以红利相诱,答应退保后扣一年费用",
+ const tempSs2=[{
+ orderTitle:"我要投诉这个大超市",
+ orderNo:"电[1]10299456",
+ restDay:6
+ orderTitle:"xxx医院乱开药方,售卖假药",
+ orderNo:"电[2]20235691",
+ orderTitle:"我想问问这家店是干啥的",
+ orderNo:"电[3]495867322",
+ orderTitle:"我要举报朝阳区奥森公园酒店",
+ orderNo:"电[2]1193849",
+ restDay:3
+ orderTitle:"我今天吃饭吃到一个石头子",
+ orderNo:"电[4]56782344",
+ restDay:9
+ //4-7天
+ const tip_green = "rgba(0, 255, 0, 1)"
+ //1-3天
+ const tip_yellow = "rgba(255, 255, 0, 1)"
+ //超期
+ const tip_red = "rgba(255, 0, 0, 1)"
+ name: "IndexTask",
+ components:{ JEllipsis },
+ loading:false,
+ textMaxLength:8,
+ dataSource3:[],
+ dataSource4:[],
+ title: '',
+ dataIndex: '',
+ key:'rowIndex',
+ width:50,
+ fixed:'left',
+ scopedSlots: {customRender: "dayWarnning"}
+ title:'剩余天数',
+ dataIndex: 'restDay',
+ width:80
+ title:'工单标题',
+ dataIndex: 'orderTitle',
+ scopedSlots: {customRender: "ellipsisText"}
+ title:'工单编号',
+ dataIndex: 'orderNo',
+ title: '操作',
+ dataIndex: 'action',
+ scopedSlots: { customRender: 'action' }
+ this.mock();
+ getTipColor(rd){
+ let num = rd.restDay
+ if(num<=0){
+ return tip_red
+ }else if(num>=1 && num<4){
+ return tip_yellow
+ }else if(num>=4){
+ return tip_green
+ this.$message.success("请根据具体业务跳转页面")
+ //this.$router.push({ path: '/comp/mytask' })
+ mock(){
+ this.dataSource1=tempSs1
+ this.dataSource2=tempSs2
+ this.dataSource3=tempSs1
+ this.dataSource4=[]
+ this.ifNullDataSource(this.dataSource4,'.tytable4')
+ ifNullDataSource(ds,tb){
+ this.$nextTick(()=>{
+ if(!ds || ds.length==0){
+ var tmp = document.createElement('img');
+ tmp.src=noDataPng
+ tmp.width=300
+ let tbclass=`${tb} .ant-table-placeholder`
+ document.querySelector(tbclass).innerHTML=""
+ document.querySelector(tbclass).appendChild(tmp)
+ handleData(){
+ this.$message.success("办理完成")
+<style>
+ .my-index-table{height:270px}
+ .my-index-table table{font-size: 14px !important;}
+ .index-container-ty .ant-card-head-title{padding-top: 6px;padding-bottom: 6px;}
+ .index-container-ty .ant-card-extra{padding:0}
+ .index-container-ty .ant-card-extra a{color:#fff}
+ .index-container-ty .ant-card-extra a:hover{color:#152ede}
+ .index-container-ty .ant-card-head-wrapper,.index-container-ty .ant-card-head{
+ line-height:24px;
+ min-height:24px;
+ /*background: #90aeff;*/
+ background: #7196fb;
+ .index-container-ty .ant-card-body{padding: 10px 12px 0px 12px}
+ /* .index-container-ty .ant-card-actions{background: #fff}
+ .index-container-ty .ant-card-actions li {margin:2px 0;}
+ .index-container-ty .ant-card-actions > li > span{width: 100%}*/
+ .index-container-ty .ant-table-footer{text-align: right;padding:6px 12px 6px 6px;background: #fff;border-top: 2px solid #f7f1f1;}
+ .index-md-title{
+ postion:relative;
+ padding-left:24px;
+ color: #fff;
+ font-size: 21px;
+ font-family: cursive;
+ .index-md-title img{
+ height:32px;
+ top: 2px;
+ left:14px;
+ .index-container-ty .ant-card-body{
+ /*border-left:1px solid #90aeff;
+ /*border-right:1px solid #90aeff;
+ border-bottom:1px solid #90aeff;*/
+ .index-container-ty .ant-table-thead > tr > th,
+ .index-container-ty .ant-table-tbody > tr > td{
+ border-bottom: 1px solid #90aeff;
+ .index-container-ty .ant-table-small > .ant-table-content > .ant-table-fixed-left > .ant-table-body-outer > .ant-table-body-inner > table > .ant-table-thead > tr > th,
+ .index-container-ty .ant-table-small > .ant-table-content > .ant-table-fixed-right > .ant-table-body-outer > .ant-table-body-inner > table > .ant-table-thead > tr > th{
+ .index-container-ty .ant-table-small > .ant-table-content > .ant-table-scroll > .ant-table-body > table > .ant-table-thead > tr > th{
+ .index-container-ty .ant-table-small{
+ border: 1px solid #90aeff;
+ .index-container-ty .ant-table-placeholder {
+ padding: 0
@@ -0,0 +1,91 @@
+ <a-card :bordered="false">
+ :pagination="false"
+ >
+ name: 'TableTotal',
+ title: '#',
+ width: '180px',
+ align: 'center',
+ dataIndex: 'rowIndex',
+ customRender: function (text, r, index) {
+ return (text !== '合计') ? (parseInt(index) + 1) : text
+ title: '姓名',
+ dataIndex: 'name',
+ title: '贡献点',
+ dataIndex: 'point',
+ title: '等级',
+ dataIndex: 'level',
+ title: '更新时间',
+ dataIndex: 'updateTime',
+ dataSource: [
+ { name: '张三', point: 23, level: 3, updateTime: '2019-8-14' },
+ { name: '小王', point: 6, level: 1, updateTime: '2019-8-13' },
+ { name: '李四', point: 53, level: 8, updateTime: '2019-8-12' },
+ { name: '小红', point: 44, level: 5, updateTime: '2019-8-11' },
+ { name: '王五', point: 97, level: 10, updateTime: '2019-8-10' },
+ { name: '小明', point: 33, level: 2, updateTime: '2019-8-10' },
+ mounted() {
+ this.tableAddTotalRow(this.columns, this.dataSource)
+ /** 表格增加合计行 */
+ tableAddTotalRow(columns, dataSource) {
+ let numKey = 'rowIndex'
+ let totalRow = { [numKey]: '合计' }
+ columns.forEach(column => {
+ let { key, dataIndex } = column
+ if (![key, dataIndex].includes(numKey)) {
+ let total = 0
+ total += /^\d+\.?\d?$/.test(data[dataIndex]) ? Number.parseInt(data[dataIndex]) : Number.NaN
+ console.log(data[dataIndex], ':', (/^\d+\.?\d?$/.test(data[dataIndex]) ? Number.parseInt(data[dataIndex]) : Number.NaN))
+ if (Number.isNaN(total)) {
+ total = '-'
+ totalRow[dataIndex] = total
+ dataSource.push(totalRow)
@@ -0,0 +1,275 @@
+ <a-button @click="handleTableCheck" type="primary">表单验证</a-button>
+ <span style="padding-left:8px;"></span>
+ <a-tooltip placement="top" title="获取值,忽略表单验证" :autoAdjustOverflow="true">
+ <a-button @click="handleTableGet" type="primary">获取值</a-button>
+ <a-tooltip placement="top" title="模拟加载1000条数据" :autoAdjustOverflow="true">
+ <a-button @click="handleTableSet" type="primary">设置值</a-button>
+ <j-editable-table
+ ref="editableTable"
+ :rowNumber="true"
+ :rowSelection="true"
+ :actionButton="true"
+ :dragSort="true"
+ style="margin-top: 8px;"
+ @selectRowChange="handleSelectRowChange">
+ <template v-slot:action="props">
+ <a @click="handleDelete(props)">{{ props.text }}</a>
+ </j-editable-table>
+ import moment from 'moment'
+ import { FormTypes } from '@/utils/JEditableTableUtil'
+ import { randomUUID, randomNumber } from '@/utils/util'
+ import JEditableTable from '@/components/jeecg/JEditableTable'
+ name: 'DefaultTable',
+ components: { JEditableTable },
+ loading: false,
+ title: '字段名称',
+ key: 'dbFieldName',
+ // width: '19%',
+ width: '300px',
+ type: FormTypes.input,
+ defaultValue: '',
+ placeholder: '请输入${title}',
+ validateRules: [
+ required: true, // 必填
+ message: '请输入${title}' // 显示的文本
+ pattern: /^[a-z|A-Z][a-z|A-Z\d_-]{0,}$/, // 正则
+ message: '${title}必须以字母开头,可包含数字、下划线、横杠'
+ unique: true,
+ message: '${title}不能重复'
+ handler(type, value, row, column, callback, target) {
+ // type 触发校验的类型(input、change、blur)
+ // value 当前校验的值
+ // callback(flag, message) 方法必须执行且只能执行一次
+ // flag = 是否通过了校验,不填写或者填写 null 代表不进行任何操作
+ // message = 提示的类型,默认使用配置的 message
+ // target 行编辑的实例对象
+ if (type === 'blur') {
+ if (value === 'abc') {
+ callback(false, '${title}不能是abc') // false = 未通过校验
+ callback(true) // true = 通过验证
+ callback(true) // 不填写或者填写 null 代表不进行任何操作
+ message: '${title}默认提示'
+ title: '文件域',
+ key: 'upload',
+ type: FormTypes.upload,
+ placeholder: '点击上传',
+ token: true,
+ responseName: 'message',
+ action: window._CONFIG['domianURL'] + '/sys/common/upload'
+ title: '字段类型',
+ key: 'dbFieldType',
+ // width: '18%',
+ type: FormTypes.select,
+ options: [ // 下拉选项
+ { title: 'String', value: 'string' },
+ { title: 'Integer', value: 'int' },
+ { title: 'Double', value: 'double' },
+ { title: 'Boolean', value: 'boolean' }
+ allowInput: true,
+ placeholder: '请选择${title}',
+ validateRules: [{ required: true, message: '请选择${title}' }]
+ title: '性别(字典)',
+ key: 'sex_dict',
+ dictCode: 'sex',
+ title: '多选测试',
+ key: 'multipleSelect',
+ props: { 'mode': 'multiple' }, // 支持多选
+ options: [
+ defaultValue: ['int', 'boolean'], // 多个默认项
+ // defaultValue: 'string,double,int', // 也可使用这种方式
+ placeholder: '这里可以多选',
+ title: '字段长度',
+ key: 'dbLength',
+ // width: '8%',
+ width: '100px',
+ type: FormTypes.inputNumber,
+ defaultValue: 32,
+ placeholder: '${title}',
+ validateRules: [{ required: true, message: '请输入${title}' }]
+ title: '日期',
+ key: 'datetime',
+ // width: '22%',
+ width: '320px',
+ type: FormTypes.datetime,
+ defaultValue: '2019-4-30 14:52:22',
+ title: '可以为空',
+ key: 'isNull',
+ type: FormTypes.checkbox,
+ customValue: ['Y', 'N'], // true ,false
+ defaultChecked: false
+ key: 'action',
+ type: FormTypes.slot,
+ slotName: 'action',
+ defaultValue: '删除'
+ selectedRowIds: []
+ this.randomData(23, false)
+ /** 表单验证 */
+ handleTableCheck() {
+ this.$refs.editableTable.getValues((error) => {
+ if (error === 0) {
+ this.$message.success('验证通过')
+ this.$message.error('验证未通过')
+ /** 获取值,忽略表单验证 */
+ handleTableGet() {
+ this.$refs.editableTable.getValues((error, values) => {
+ console.log('values:', values)
+ }, false)
+ console.log('deleteIds:', this.$refs.editableTable.getDeleteIds())
+ this.$message.info('获取值成功,请看控制台输出')
+ /** 模拟加载1000条数据 */
+ handleTableSet() {
+ this.randomData(1000, true)
+ handleSelectRowChange(selectedRowIds) {
+ this.selectedRowIds = selectedRowIds
+ /* 随机生成数据 */
+ randomData(size, loading = false) {
+ if (loading) {
+ this.loading = true
+ let randomDatetime = () => {
+ let time = parseInt(randomNumber(1000, 9999999999999))
+ return moment(new Date(time)).format('YYYY-MM-DD HH:mm:ss')
+ let begin = Date.now()
+ let values = []
+ for (let i = 0; i < size; i++) {
+ values.push({
+ id: randomUUID(),
+ dbFieldName: `name_${i + 1}`,
+ // dbFieldTxt: randomString(10),
+ multipleSelect: ['string', ['int', 'double', 'boolean'][randomNumber(0, 2)]],
+ dbFieldType: ['string', 'int', 'double', 'boolean'][randomNumber(0, 3)],
+ dbLength: randomNumber(0, 233),
+ datetime: randomDatetime(),
+ isNull: ['Y', 'N'][randomNumber(0, 1)]
+ this.dataSource = values
+ let end = Date.now()
+ let diff = end - begin
+ if (loading && diff < size) {
+ this.loading = false
+ }, size - diff)
+ handleDelete(props) {
+ let { rowId, target } = props
+ target.removeRows(rowId)
@@ -0,0 +1,70 @@
+ :maxHeight="400"
+ :disabled="true"
+ name: 'ReadOnlyTable',
+ title: '输入框',
+ key: 'input',
+ placeholder: '清输入'
+ title: '下拉框',
+ key: 'select',
+ placeholder: '请选择'
+ title: '多选框',
+ key: 'checkbox',
+ customValue: [true, false]
+ type: FormTypes.datetime
+ { input: 'hello', select: 'int', checkbox: true, datetime: '2019-6-17 14:50:48' },
+ { input: 'world', select: 'string', checkbox: false, datetime: '2019-6-16 14:50:48' },
+ { input: 'one', select: 'double', checkbox: true, datetime: '2019-6-17 15:50:48' },
+ { input: 'two', select: 'boolean', checkbox: false, datetime: '2019-6-14 14:50:48' },
+ { input: 'three', select: '', checkbox: false, datetime: '2019-6-13 14:50:48' }
@@ -0,0 +1,129 @@
+ @valueChange="handleValueChange"
+ name: 'ThreeLinkage',
+ title: '省/直辖市/自治区',
+ key: 's1',
+ width: '240px',
+ placeholder: '请选择${title}'
+ title: '市',
+ key: 's2',
+ title: '县/区',
+ key: 's3',
+ mockData: [
+ { label: '北京市', value: '110000', parent: null },
+ { label: '天津市', value: '120000', parent: null },
+ { label: '河北省', value: '130000', parent: null },
+ { label: '上海市', value: '310000', parent: null },
+ { label: '北京市', value: '110100', parent: '110000' },
+ { label: '天津市市', value: '120100', parent: '120000' },
+ { label: '石家庄市', value: '130100', parent: '130000' },
+ { label: '唐山市', value: '130200', parent: '130000' },
+ { label: '秦皇岛市', value: '130300', parent: '130000' },
+ { label: '上海市', value: '310100', parent: '310000' },
+ { label: '东城区', value: '110101', parent: '110100' },
+ { label: '西城区', value: '110102', parent: '110100' },
+ { label: '朝阳区', value: '110105', parent: '110100' },
+ { label: '和平区', value: '120101', parent: '120000' },
+ { label: '河东区', value: '120102', parent: '120000' },
+ { label: '河西区', value: '120103', parent: '120000' },
+ { label: '黄浦区', value: '310101', parent: '310100' },
+ { label: '徐汇区', value: '310104', parent: '310100' },
+ { label: '长宁区', value: '310105', parent: '310100' },
+ { label: '长安区', value: '130102', parent: '130100' },
+ { label: '桥西区', value: '130104', parent: '130100' },
+ { label: '新华区', value: '130105', parent: '130100' },
+ { label: '路南区', value: '130202', parent: '130200' },
+ { label: '路北区', value: '130203', parent: '130200' },
+ { label: '古冶区', value: '130204', parent: '130200' },
+ { label: '海港区', value: '130302', parent: '130300' },
+ { label: '山海关区', value: '130303', parent: '130300' },
+ { label: '北戴河区', value: '130304', parent: '130300' },
+ // 初始化数据
+ this.columns[0].options = this.request(null)
+ request(parentId) {
+ return this.mockData.filter(i => i.parent === parentId)
+ /** 当选项被改变时,联动其他组件 */
+ handleValueChange(event) {
+ const { type, row, column, value, target } = event
+ if (type === FormTypes.select) {
+ // 第一列
+ if (column.key === 's1') {
+ // 设置第二列的 options
+ this.columns[1].options = this.request(value)
+ // 清空后两列的数据
+ target.setValues([{
+ rowKey: row.id,
+ values: { s2: '', s3: '' }
+ }])
+ this.columns[2].options = []
+ } else
+ // 第二列
+ if (column.key === 's2') {
+ this.columns[2].options = this.request(value)
+ values: { s3: '' }
@@ -109,7 +109,7 @@ export default {
parentNode.children = res.result.map(item => {
return {
id: item.accountId,
- label: item.userName + ' ' + item.authName
+ label: item.userName + '\xa0\xa0\xa0\xa0\xa0\xa0\xa0\xa0\xa0\xa0\xa0\xa0' + item.authName
})
callback()
@@ -127,10 +127,13 @@ export default {
//我参与的
getAction('/ctop/projectMember/participateList', { userId: this.userInfo().id }).then(res => {
if (res.code == 0) {
- this.options = res.result.map(item => {
+ var data = res.result.filter(item => {
+ return item.mediaId == 2
+ this.options = data.map(item => {
id: item.projectId,
- label: item.projectName,
+ label: item.projectName + '\xa0\xa0\xa0\xa0\xa0\xa0\xa0\xa0\xa0\xa0\xa0\xa0' + item.advertiserName,
children: null
+.select-table .ant-table-thead > tr > th,
+.select-table .ant-table-tbody > tr > td {
+ padding: 0 !important;
+.select-table .ant-table {
+ <a-form-item
+ label="项目名称"
+ :label-col="labelCol"
+ :wrapper-col="wrapperCol"
+ v-clickoutside="handleClose"
+ style="width:100%"
+ class="select-table"
+ <a-input placeholder="请选择项目" @focus=";(topMiddle = true), allData()" v-model="keyValue" @change="getData" />
+ <div
+ style="background:white;padding:10px;box-shadow: 0 2px 8px 0 rgba(0,0,0,.15);position:relative;z-index:1000"
+ v-if="topMiddle"
+ :showHeader="false"
+ :dataSource="data"
+ :scroll="{ y: 300 }"
+ :customRow="rowClick"
+ <span slot="mediaId" slot-scope="text">{{ text == '1' ? '头条' : '快手' }}</span>
+import { getAction, postAction } from '@/api/manage'
+import moment from 'moment'
+import { mapGetters } from 'vuex'
+import jq from 'jquery'
+const clickoutside = {
+ // 初始化指令
+ bind(el, binding, vnode) {
+ function documentHandler(e) {
+ // 这里判断点击的元素是否是本身,是本身,则返回
+ if (el.contains(e.target)) {
+ // 判断指令中是否绑定了函数
+ if (binding.expression) {
+ // 如果绑定了函数 则调用那个函数,此处binding.value就是handleClose方法
+ binding.value(e)
+ // 给当前元素绑定个私有变量,方便在unbind中可以解除事件监听
+ el.__vueClickOutside__ = documentHandler
+ document.addEventListener('click', documentHandler)
+ update() {},
+ unbind(el, binding) {
+ // 解除事件监听
+ document.removeEventListener('click', el.__vueClickOutside__)
+ delete el.__vueClickOutside__
+const columns = [
+ dataIndex: 'projectName',
+ align: 'center'
+ dataIndex: 'mediaId',
+ scopedSlots: { customRender: 'mediaId' },
+ width: 80,
+ dataIndex: 'advertiserName',
+]
+ name: 'BaseForm',
+ components: {},
+ directives: { clickoutside },
+ projectId: {
+ default() {
+ return ''
+ labelCol: {
+ xs: { span: 24 },
+ sm: { span: 5 }
+ wrapperCol: {
+ sm: { span: 12 }
+ selectedRowKeys: [],
+ selectedRowKeysValue: [],
+ topMiddle: false,
+ keyValue: '',
+ columns,
+ data: [],
+ dataElse: [],
+ rowClick: (record, index) => ({
+ // 事件
+ var str = record.mediaId == '1' ? '头条' : '快手'
+ this.keyValue = record.projectName + ' ' + str
+ this.topMiddle = false
+ this.data = this.dataElse
+ this.$emit('update:projectId', record.projectId)
+ computed: {},
+ filters: {},
+ ...mapGetters(['nickname', 'avatar', 'userInfo']),
+ onSelectChange(selectedRowKeys, selectionRows) {
+ this.selectedRowKeys = selectedRowKeys
+ this.selectedRowKeysValue = selectionRows.map(item => {
+ return { orientationId: item.orientationId, orientationName: item.orientationName }
+ getData() {
+ if (this.keyValue != '') {
+ this.data = this.dataElse.filter(item => {
+ return item.projectName.toLowerCase().indexOf(this.keyValue.toLowerCase()) > -1
+ handleClose() {
+ allData() {
+ getAction('/ctop/projectMember/participateList', { userId: this.userInfo().id }).then(res => {
+ if (res.code == 0) {
+ this.data = res.result.map((item, index) => {
+ ...item,
+ projectId: item.projectId + '',
+ key: index
+ this.dataElse = res.result.map((item, index) => {
+ projectId(n, o) {
+ if (n == '') {
+ this.keyValue = ''
+ mounted: function() {
+ this.allData()
+<style type="text/css">
+.plug-timer-grid {
+.plug-timer-grid td,
+.plug-timer-grid th {
+ border: 1px solid #97b4d1;
+ text-align: center; /*cursor:pointer;*/
+ font-size: 10px;
+ line-height: 10px;
+.Selected {
+ background-color: rgb(102, 162, 243);
+ opacity: 0.5;
+ border-collapse: collapse;
+ z-index: 4;
+.plug-timer-grid thead tr {
+ display: table-row;
+ vertical-align: inherit;
+ border-color: inherit;
+.group-creat table td {
+ height: 20px;
+ max-width: 5px;
+ border: 1px solid #dfe6ec;
+ transition: background 0.5s;
+ -webkit-transition: background 0.5s;
+.plug-timer-grid tbody th {
+ width: 4%;
+.plug-timer-grid tbody tr td {
+ width: 2%;
+/*.clear{*/
+/* margin:20px 0px 20px 0px;*/
+/*}*/
@@ -42,6 +42,9 @@
>
<span slot="mediaId" slot-scope="text">{{ text == 1 ? '头条' : '快手' }}</span>
<span slot="action" slot-scope="text, record">
+ <a @click="project(record)">绑定项目</a>
+ <a-divider type="vertical" />
<a @click="handleEdit(record)">编辑</a>
<a-divider type="vertical" />
@@ -55,22 +58,46 @@
<!-- 表单区域 -->
<userAllocation-modal ref="modalForm" @ok="modalFormOk"></userAllocation-modal>
+ <!-- 添加项目成员 -->
+ <a-modal title="项目绑定" v-model="visibleAdd" @ok="handleOkAdd" :confirmLoading="confirmLoading">
+ <!-- /sys/user/getAllUserList -->
+ <treeSelect ref="treeSelect" :appId.sync="projectId" :multiple="false" :mediaId="mediaId" style="width:100%" />
+ <!-- <a-select
+ v-model="projectId"
+ placeholder="请输入项目名称"
+ showSearch
+ optionFilterProp="children"
+ :filterOption="filterOption"
+ <a-select-option :value="item.id" v-for="item of options" :key="item.id">
+ {{ item.projectName }}
+ </a-select-option>
+ </a-select> -->
</a-card>
</template>
<script>
import UserAllocationModal from './modules/UserAllocationModal'
import { JeecgListMixin } from '@/mixins/JeecgListMixin'
+import { httpAction, getAction, deleteAction } from '@/api/manage'
+import treeSelect from './modules/Treeselect'
export default {
name: 'UserAllocationList',
mixins: [JeecgListMixin],
components: {
- UserAllocationModal
+ UserAllocationModal,
+ treeSelect
data() {
description: '账号绑定管理页面',
+ visibleAdd: false,
// 表头
columns: [
{
@@ -132,7 +159,11 @@ export default {
deleteBatch: '/ctop/userAllocation/deleteBatch',
exportXlsUrl: 'ctop/userAllocation/exportXls',
importExcelUrl: 'ctop/userAllocation/importExcel'
+ confirmLoading: false,
+ projectId: '',
+ accountId: '',
+ mediaId: ''
computed: {
@@ -140,7 +171,43 @@ export default {
return `${window._CONFIG['domianURL']}/${this.url.importExcelUrl}`
- methods: {}
+ filterOption(input, option) {
+ return option.componentOptions.children[0].text.toLowerCase().indexOf(input.toLowerCase()) >= 0
+ project(item) {
+ console.log(item)
+ this.visibleAdd = true
+ this.accountId = item.accountId
+ this.$refs.treeSelect.getParticipateList(item.mediaId)
+ // getAction('/ctop/project/getProjectByCompany', { userId: this.userInfo().id, mediaId: item.mediaId }).then(
+ // res => {
+ // console.log(res)
+ // if (res.success) {
+ // this.options = res.result
+ // )
+ handleOkAdd(e) {
+ var params = {}
+ params.projectId = this.projectId
+ params.accountId = this.accountId
+ this.confirmLoading = true
+ getAction('/ctop/userAllocation/accountTurnProject', params).then(res => {
+ this.confirmLoading = false
+ this.visibleAdd = false
+ this.projectId = ''
+ this.$message.success('绑定成功')
+ this.loadData()
+ this.$message.error(res.message)
</script>
<style scoped>
@@ -0,0 +1,153 @@
+.select-project {
+ width: 50%;
+ <div class="select-project">
+ <treeselect
+ :disable-branch-nodes="!multiple"
+ :options="options"
+ :load-options="loadOptions"
+ placeholder="请选择项目"
+ v-model="value"
+ :value-consists-of="valueConsistsOf"
+ @select="update"
+ @input="emitValue"
+ :limit="2"
+ :limitText="
+ count => {
+ return '隐藏' + count + '条'
+ "
+ noChildrenText="该广告主下暂无项目"
+ noOptionsText="暂无项目"
+// import the component
+import Treeselect from '@riophae/vue-treeselect'
+// import the styles
+import '@riophae/vue-treeselect/dist/vue-treeselect.css'
+import { LOAD_CHILDREN_OPTIONS } from '@riophae/vue-treeselect'
+// We just use `setTimeout()` here to simulate an async operation
+// instead of requesting a real API server for demo purpose.
+ data: () => ({
+ value: null,
+ valueConsistsOf: 'LEAF_PRIORITY',
+ }),
+ appId: {}
+ components: { Treeselect },
+ $route(n, o) {},
+ appId: {
+ handler(n, o) {
+ console.log(n)
+ if (n.length == 0) {
+ if (this.multiple) {
+ this.value = []
+ this.value = ''
+ deep: true
+ update(node, id) {
+ console.log(node, id)
+ getAction('/ctop/project/getProjectByAdvertiserAndMediaId', {
+ advertiserId: node.id,
+ mediaId: this.mediaId
+ }).then(res => {
+ console.log(res)
+ if (res.result.length > 0) {
+ node.children = res.result.map(item => {
+ id: item.id,
+ label: item.projectName
+ new Error('Failed to load options: network error.')
+ emitValue() {
+ this.$emit('update:appId', this.value)
+ getChildren() {},
+ loadOptions({ action, parentNode, callback }) {
+ // Typically, do the AJAX stuff here.
+ // Once the server has responded,
+ // assign children options to the parent node & call the callback.
+ if (action === LOAD_CHILDREN_OPTIONS) {
+ advertiserId: parentNode.id,
+ parentNode.children = res.result.map(item => {
+ callback()
+ parentNode.children = []
+ callback(new Error('Failed to load options: network error.'))
+ getParticipateList(mediaId) {
+ this.mediaId = mediaId
+ this.value = null
+ getAction('/ctop/advertiser/getAdvertiserByCompany', { userId: this.userInfo().id }).then(res => {
+ this.options = res.result.map(item => {
+ label: item.name,
+ children: null
+ mounted() {}
@@ -11,7 +11,19 @@
<a-spin :spinning="confirmLoading">
<a-form :form="form">
<a-form-item :labelCol="labelCol" :wrapperCol="wrapperCol" label="账户所属人">
- <a-input placeholder="请输入userName" v-decorator="['userName', {}]" disabled />
+ <!-- <a-input placeholder="请输入userName" v-decorator="['userName', {}]" disabled /> -->
+ v-decorator="['userId', {}]"
+ placeholder="请输入userName"
+ <a-select-option :value="item.userId" v-for="(item,index) of options" :key="index">
+ {{ item.realName }}
</a-form-item>
<a-form-item :labelCol="labelCol" :wrapperCol="wrapperCol" label="账号id">
<a-input placeholder="请输入账户id --授权" v-decorator="['accountId', {}]" disabled />
@@ -64,10 +76,10 @@
-import { httpAction } from '@/api/manage'
+import { httpAction, getAction } from '@/api/manage'
import pick from 'lodash.pick'
import moment from 'moment'
-
name: 'UserAllocationModal',
@@ -90,15 +102,25 @@ export default {
url: {
add: '/ctop/userAllocation/add',
edit: '/ctop/userAllocation/edit'
+ options: []
created() {},
methods: {
add() {
this.edit({})
edit(record) {
+ getAction('/sys/user/getAllUserListByCompany', { userId: this.userInfo().id }).then(res => {
+ this.options = res.result
this.form.resetFields()
this.model = Object.assign({}, record)
this.visible = true
@@ -116,8 +138,8 @@ export default {
'accountName',
'authName',
'mediaId',
- "warningAmount",
- "warningProportion"
+ 'warningAmount',
+ 'warningProportion'
)
//时间格式化
@@ -143,6 +165,9 @@ export default {
method = 'put'
let formData = Object.assign(this.model, values)
+ formData.userName = this.options.filter(item => {
+ return item.userId == values.userId
+ })[0].realName
console.log(formData)
@@ -0,0 +1,209 @@
+ <a-col :md="6" :sm="8">
+ <a-form-item label="日期">
+ <a-input placeholder="请输入日期" v-model="queryParam.date"></a-input>
+ <a-form-item label="账户ID">
+ <a-input placeholder="请输入账户ID" v-model="queryParam.accountId"></a-input>
+ <a-form-item label="快手ID">
+ <a-input placeholder="请输入快手ID" v-model="queryParam.kid"></a-input>
+ <a-form-item label="广告主名称">
+ <a-input placeholder="请输入广告主名称" v-model="queryParam.advertiserName"></a-input>
+ <a-form-item label="广告主创建时间">
+ <a-input placeholder="请输入广告主创建时间" v-model="queryParam.advertiserCreateTime"></a-input>
+ <a-col :md="6" :sm="8" >
+ <!-- 操作按钮区域 -->
+ <div class="table-operator">
+ <a-button @click="handleAdd" type="primary" icon="plus">新增</a-button>
+ <a-button type="primary" icon="download" @click="handleExportXls('代理商报表')">导出</a-button>
+ <a-upload name="file" :showUploadList="false" :multiple="false" :headers="tokenHeader" :action="importExcelUrl" @change="handleImportExcel">
+ <a-button type="primary" icon="import">导入</a-button>
+ </a-upload>
+ <!-- table区域-begin -->
+ ref="table"
+ size="middle"
+ <!-- table区域-end -->
+ <!-- 表单区域 -->
+ <kuaishouReportDailyAgent-modal ref="modalForm" @ok="modalFormOk"></kuaishouReportDailyAgent-modal>
+ import KuaishouReportDailyAgentModal from './modules/KuaishouReportDailyAgentModal'
+ name: "KuaishouReportDailyAgentList",
+ mixins:[JeecgListMixin],
+ KuaishouReportDailyAgentModal
+ description: '代理商报表管理页面',
+ dataIndex: 'date'
+ title: '账户ID',
+ dataIndex: 'accountId'
+ title: '快手ID',
+ dataIndex: 'kid'
+ title: '广告主名称',
+ dataIndex: 'advertiserName'
+ title: '广告主创建时间',
+ dataIndex: 'advertiserCreateTime'
+ title: '有消费计划数',
+ dataIndex: 'costCampaignCount'
+ title: '总余额',
+ dataIndex: 'balance'
+ title: '总消耗',
+ dataIndex: 'cost'
+ title: '现金消耗',
+ dataIndex: 'xianjinCost'
+ title: '后返消耗',
+ dataIndex: 'fandianCost'
+ title: '框返消耗',
+ dataIndex: 'kuangfanCost'
+ title: '激励账户消耗',
+ dataIndex: 'jiliCost'
+ title: '信用账户消耗',
+ dataIndex: 'xinyongCost'
+ title: '封面曝光数',
+ dataIndex: 'fengmianShowCount'
+ title: '封面点击数',
+ dataIndex: 'fengmianClickCount'
+ title: '素材曝光数',
+ dataIndex: 'sucaiShowCount'
+ title: '行为数',
+ dataIndex: 'convertCount'
+ title: '封面点击率',
+ dataIndex: 'fengmianClickRate'
+ title: '转化点击率',
+ dataIndex: 'convertClickRate'
+ url: {
+ list: "/report/kuaishouReportDailyAgent/list",
+ delete: "/report/kuaishouReportDailyAgent/delete",
+ deleteBatch: "/report/kuaishouReportDailyAgent/deleteBatch",
+ exportXlsUrl: "report/kuaishouReportDailyAgent/exportXls",
+ importExcelUrl: "report/kuaishouReportDailyAgent/importExcel",
+ importExcelUrl: function(){
+ return `${window._CONFIG['domianURL']}/${this.url.importExcelUrl}`;
+ @import '~@assets/less/common.less'
@@ -0,0 +1,164 @@
+ <a-button type="primary" icon="download" @click="handleExportXls('代理商日汇总表')">导出</a-button>
+ <kuaishouReportDailyAgentSum-modal ref="modalForm" @ok="modalFormOk"></kuaishouReportDailyAgentSum-modal>
+ import KuaishouReportDailyAgentSumModal from './modules/KuaishouReportDailyAgentSumModal'
+ name: "KuaishouReportDailyAgentSumList",
+ KuaishouReportDailyAgentSumModal
+ description: '代理商日汇总表管理页面',
+ list: "/report/kuaishouReportDailyAgentSum/list",
+ delete: "/report/kuaishouReportDailyAgentSum/delete",
+ deleteBatch: "/report/kuaishouReportDailyAgentSum/deleteBatch",
+ exportXlsUrl: "report/kuaishouReportDailyAgentSum/exportXls",
+ importExcelUrl: "report/kuaishouReportDailyAgentSum/importExcel",
@@ -0,0 +1,238 @@
+ :title="title"
+ :width="800"
+ @cancel="handleCancel"
+ <a-spin :spinning="confirmLoading">
+ <a-form :form="form">
+ :labelCol="labelCol"
+ :wrapperCol="wrapperCol"
+ label="日期">
+ <a-date-picker v-decorator="[ 'date', validatorRules.date ]" />
+ label="账户ID">
+ <a-input placeholder="请输入账户ID" v-decorator="['accountId', validatorRules.accountId ]" />
+ label="快手ID">
+ <a-input placeholder="请输入快手ID" v-decorator="['kid', {}]" />
+ label="广告主名称">
+ <a-input placeholder="请输入广告主名称" v-decorator="['advertiserName', {}]" />
+ label="广告主创建时间">
+ <a-date-picker v-decorator="[ 'advertiserCreateTime', {}]" />
+ label="有消费计划数">
+ <a-input-number v-decorator="[ 'costCampaignCount', {}]" />
+ label="总余额">
+ <a-input-number v-decorator="[ 'balance', {}]" />
+ label="总消耗">
+ <a-input-number v-decorator="[ 'cost', {}]" />
+ label="现金消耗">
+ <a-input-number v-decorator="[ 'xianjinCost', {}]" />
+ label="后返消耗">
+ <a-input-number v-decorator="[ 'fandianCost', {}]" />
+ label="框返消耗">
+ <a-input-number v-decorator="[ 'kuangfanCost', {}]" />
+ label="激励账户消耗">
+ <a-input-number v-decorator="[ 'jiliCost', {}]" />
+ label="信用账户消耗">
+ <a-input-number v-decorator="[ 'xinyongCost', {}]" />
+ label="封面曝光数">
+ <a-input-number v-decorator="[ 'fengmianShowCount', {}]" />
+ label="封面点击数">
+ <a-input-number v-decorator="[ 'fengmianClickCount', {}]" />
+ label="素材曝光数">
+ <a-input-number v-decorator="[ 'sucaiShowCount', {}]" />
+ label="行为数">
+ <a-input-number v-decorator="[ 'convertCount', {}]" />
+ label="封面点击率">
+ <a-input-number v-decorator="[ 'fengmianClickRate', {}]" />
+ label="转化点击率">
+ <a-input-number v-decorator="[ 'convertLickRate', {}]" />
+ import { httpAction } from '@/api/manage'
+ import pick from 'lodash.pick'
+ import moment from "moment"
+ name: "KuaishouReportDailyAgentModal",
+ title:"操作",
+ model: {},
+ sm: { span: 5 },
+ sm: { span: 16 },
+ form: this.$form.createForm(this),
+ validatorRules:{
+ date:{rules: [{ required: true, message: '请输入日期!' }]},
+ accountId:{rules: [{ required: true, message: '请输入账户ID!' }]},
+ add: "/report/kuaishouReportDailyAgent/add",
+ edit: "/report/kuaishouReportDailyAgent/edit",
+ created () {
+ add () {
+ this.edit({});
+ edit (record) {
+ this.form.resetFields();
+ this.model = Object.assign({}, record);
+ this.$nextTick(() => {
+ this.form.setFieldsValue(pick(this.model,'accountId','kid','advertiserName','costCampaignCount','balance','cost','xianjinCost','fandianCost','kuangfanCost','jiliCost','xinyongCost','fengmianShowCount','fengmianClickCount','sucaiShowCount','convertCount','fengmianClickRate','convertLickRate'))
+ //时间格式化
+ this.form.setFieldsValue({date:this.model.date?moment(this.model.date):null})
+ this.form.setFieldsValue({advertiserCreateTime:this.model.advertiserCreateTime?moment(this.model.advertiserCreateTime):null})
+ close () {
+ this.$emit('close');
+ handleOk () {
+ const that = this;
+ // 触发表单验证
+ this.form.validateFields((err, values) => {
+ if (!err) {
+ that.confirmLoading = true;
+ let httpurl = '';
+ let method = '';
+ if(!this.model.id){
+ httpurl+=this.url.add;
+ method = 'post';
+ httpurl+=this.url.edit;
+ method = 'put';
+ let formData = Object.assign(this.model, values);
+ formData.date = formData.date?formData.date.format():null;
+ formData.advertiserCreateTime = formData.advertiserCreateTime?formData.advertiserCreateTime.format():null;
+ console.log(formData)
+ httpAction(httpurl,formData,method).then((res)=>{
+ that.$message.success(res.message);
+ that.$emit('ok');
+ that.$message.warning(res.message);
+ }).finally(() => {
+ that.confirmLoading = false;
+ that.close();
+ handleCancel () {
@@ -0,0 +1,245 @@
+ <a-drawer
+ placement="right"
+ :closable="false"
+ @close="close"
+ <a-button type="primary" @click="handleOk">确定</a-button>
+ <a-button type="primary" @click="handleCancel">取消</a-button>
+ </a-drawer>
+/** Button按钮间距 */
+ .ant-btn {
+ margin-left: 30px;
+ margin-bottom: 30px;
+ float: right;
+ <a-input-number v-decorator="[ 'convertClickRate', {}]" />
+ name: "KuaishouReportDailyAgentSumModal",
+ add: "/report/kuaishouReportDailyAgentSum/add",
+ edit: "/report/kuaishouReportDailyAgentSum/edit",
+ this.form.setFieldsValue(pick(this.model,'accountId','kid','advertiserName','costCampaignCount','balance','cost','xianjinCost','fandianCost','kuangfanCost','jiliCost','xinyongCost','fengmianShowCount','fengmianClickCount','sucaiShowCount','convertCount','fengmianClickRate','convertClickRate'))
@@ -0,0 +1,96 @@
+ <a-form-item label="产品名称">
+ <a-input placeholder="请输入产品名称" v-model="queryParam.name"></a-input>
+ <kuaishouAppProduct-modal ref="modalForm" @ok="modalFormOk"></kuaishouAppProduct-modal>
+ import KuaishouAppProductModal from './modules/KuaishouAppProductModal'
+ name: "KuaishouAppProductList",
+ KuaishouAppProductModal
+ description: '快手推广产品管理页面',
+ title: '产品名称',
+ dataIndex: 'name'
+ title: '投放日期',
+ dataIndex: 'createTime'
+ list: "/ctop/kuaishouAppProduct/list",
+ delete: "/ctop/kuaishouAppProduct/delete",
+ deleteBatch: "/ctop/kuaishouAppProduct/deleteBatch",
+ exportXlsUrl: "ctop/kuaishouAppProduct/exportXls",
+ importExcelUrl: "ctop/kuaishouAppProduct/importExcel",
@@ -0,0 +1,125 @@
+ label="产品名称">
+ <a-input placeholder="请输入产品名称" v-decorator="['name', validatorRules.name ]" />
+ name: "KuaishouAppProductModal",
+ name:{rules: [{ required: true, message: '请输入产品名称!' }]},
+ add: "/kuaishou.modules.app/kuaishouAppProduct/add",
+ edit: "/kuaishou.modules.app/kuaishouAppProduct/edit",
+ this.form.setFieldsValue(pick(this.model,'name'))
@@ -67,7 +67,18 @@
:pagination="ipagination"
:rowSelection="{ selectedRowKeys: selectedRowKeys, onChange: onSelectChange }"
- <a slot="campaignName" slot-scope="text, record" @click="toDetail(record)">{{ text }}</a>
+ <template slot="campaignName" slot-scope="text, record">
+ <div style="display:flex;justify-content: center;">
+ <a @click="toDetail(record)" class="count" v-show="!record.editName">{{ text }}</a>
+ <a-input v-show="record.editName" v-model="record.campaignName" style="width:150px" @fouse.stop />
+ <a-icon
+ :type="record.editName ? 'check' : 'edit'"
+ @click.stop=";(record.editName = !record.editName), editShowName(record)"
+ style="margin-left:10px"
+ class="count"
<a-switch v-model="record.showSwich" @change="onChangeSwitch(record)" />
</span>
@@ -121,7 +132,7 @@ import Treeselect from '@/views/modules/Statistics/components/Treeselect.vue'
var columns = [
- title: '操作',
+ title: '开关',
align: 'center',
dataIndex: 'action',
fixed: 'left',
@@ -136,7 +147,6 @@ var columns = [
width: 300,
scopedSlots: { customRender: 'campaignName' }
title: '计划单日预算金额',
@@ -190,6 +200,8 @@ export default {
data: function() {
+ visibleEdit: false,
allType: '1',
duration: 1000,
showEdit: false,
@@ -208,27 +220,7 @@ export default {
rowClick: (record, index) => ({
// 事件
on: {
- dblclick: () => {
- // 点击改行时要做的事情
- // localStorage.setItem('advertisingGroupKey', record.campaignId)
- // localStorage.setItem('accountId', this.appId)
- // if (localStorage.getItem('advertisingGroup')) {
- // var dataElse = JSON.parse(localStorage.getItem('advertisingGroup'))
- // console.log(dataElse)
- // for (let i = 0; i < dataElse.length; i++) {
- // if (dataElse[i].key == record.key) {
- // this.$router.replace({ path: '/account/advertisingGroup' })
- // return
- // }
- // dataElse.push(record)
- // localStorage.setItem('advertisingGroup', JSON.stringify(dataElse))
- // } else {
- // var data = [record]
- // localStorage.setItem('advertisingGroup', JSON.stringify(data))
+ dblclick: () => {}
}),
ipagination: {
@@ -246,7 +238,10 @@ export default {
total: 0
- url: {}
+ url: {},
+ type: '',
+ campaignName: '',
+ campaignBudget: 'UNLIMITED'
filters: {
@@ -272,6 +267,7 @@ export default {
+ handleOkEdit(e) {},
toDetail(record) {
localStorage.setItem('advertisingGroupKey', record.campaignId)
localStorage.setItem('accountId', this.appId)
@@ -365,6 +361,7 @@ export default {
...v,
key: index,
edit: false,
+ editName: false,
showSwich: v.putStatus == 1 ? true : false
@@ -422,6 +419,23 @@ export default {
console.log(item)
+ editShowName(item) {
+ if (!item.editName) {
+ params.accountId = this.appId + ''
+ params.campaignId = item.campaignId
+ params.campaignName = item.campaignName
+ postAction('/kuaishou/batch/updateCampaign', params).then(res => {
+ if (res.result.code == 0) {
+ this.$message.success('修改成功')
+ this.addUser()
+ this.$message.error(res.result.message)
dianji() {
if (this.appId == '') {
this.$message.error('尚未选择需要创建的账户')
@@ -63,7 +63,9 @@
+ <span slot="actionTwo" slot-scope="text, record">
+ <a @click="editDetail(record)">编辑</a>
<span slot="status" slot-scope="text">{{ text | status }}</span>
<span slot="putStatus" slot-scope="text">{{ text | putStatus }}</span>
<span slot="createChannel" slot-scope="text">{{ text | createChannel }}</span>
@@ -152,7 +154,7 @@ import { deleteAction, getAction, postAction } from '@/api/manage'
import { mapGetters } from 'vuex'
@@ -185,6 +187,14 @@ var columns = [
width: 250
+ dataIndex: 'actionTwo',
+ fixed: 'left',
+ width: 100,
+ scopedSlots: { customRender: 'actionTwo' }
title: '广告组状态',
dataIndex: 'status',
@@ -290,26 +300,7 @@ export default {
- // localStorage.setItem('originalityKey', record.unitId)
- // localStorage.setItem('campaignId', record.campaignId)
- // if (localStorage.getItem('originality')) {
- // var dataElse = JSON.parse(localStorage.getItem('originality'))
- // if (dataElse[i].key == record.unitId) {
- // this.$router.replace({ path: '/account/originality' })
- // localStorage.setItem('originality', JSON.stringify(dataElse))
- // localStorage.setItem('originality', JSON.stringify(data))
@@ -426,6 +417,7 @@ export default {
this.getDataList(activeKey)
+ editDetail(item) {},
// 点击改行时要做的事情
localStorage.setItem('originalityKey', record.unitId)
@@ -0,0 +1,166 @@
+.actor-photo-list {
+ padding-left: 0;
+ li {
+ margin: 10px;
+ height: 380px;
+ border: 1px solid #f2f2f2;
+ list-style: none;
+ padding: 10px;
+ img,
+ video {
+ // margin-top: auto;
+ // margin-bottom: auto;
+ // top: 0;
+ // bottom: 0;
+ // position: absolute;
+ // max-height: 350px;
+ <a-modal title="选择素材" v-model="visibleMatemal" @ok="handleOk" @cancel="close" :width="1000">
+ <ul class="actor-photo-list">
+ <a-checkbox-group
+ v-model="checkArr"
+ style="width:100%; display: flex;padding-left: 0;"
+ @change="onChangeCheck"
+ <li v-for="(item, index) of dataSource" :key="index">
+ <a-checkbox :value="item" style="position:absolute;z-index:100;padding-right:30px">
+ <video
+ class="video"
+ v-if="active == 'video'"
+ :src="item.url"
+ controls="controls"
+ style="min-height:160px"
+ 您的浏览器不支持 video 标签。
+ </video>
+ <img :src="item.url" v-else alt="" />
+ </a-checkbox>
+ </li>
+ </a-checkbox-group>
+ </ul>
+ <div style="text-align:right">
+ <a-pagination
+ :showTotal="ipagination.showTotal"
+ style="float:right"
+ v-if="dataSource.length > 0"
+ showQuickJumper
+ :pageSize.sync="ipagination.pageSize"
+ :total="ipagination.total"
+ v-model="ipagination.current"
+ @change="getDataSource"
+import { getAction, postAction, postFile } from '@/api/manage'
+import { stopOtherVideo, closeAllVideoFun } from '@/utils/videoControl' // 停止除当前外的其他视频播放,及停止所有视频播放的方法
+ name: 'check-matemal',
+ list: '/kuaishou/batch/getVideoList'
+ visibleMatemal: false,
+ columns: [],
+ checkArr: [],
+ active: '',
+ joinVideo: {},
+ pageSize: 4,
+ watch: {},
+ updated() {
+ stopOtherVideo()
+ showCheck(typeName, url, typeString) {
+ this.dataSource = []
+ this.visibleMatemal = true
+ this.active = typeString
+ params.accountId = localStorage.getItem('accountId')
+ params.materialType = typeName
+ params.pageSize = this.ipagination.pageSize
+ params.pageNo = this.ipagination.current
+ this.url.list = url
+ this.getData(url, params)
+ getData(url, params) {
+ getAction(url, params).then(res => {
+ this.dataSource = res.result.records
+ this.ipagination.total = res.result.total
+ this.visibleMatemal = false
+ this.checkArr = []
+ this.ipagination.current = 1
+ this.$emit('showVideo', this.joinVideo, this.active)
+ close() {},
+ getDataSource(page, pageSize) {
+ this.ipagination.current = page
+ params.materialType = this.numberType
+ params.pageNo = page
+ this.getData(this.url.list, params)
+ onChangeCheck(checkedList) {
+ console.log(checkedList)
+ //片头
+ if (this.checkArr.length > 1) {
+ this.checkArr.shift()
+ this.joinVideo = checkedList[0]
+ } else if (this.checkArr.length == 1) {
+ } else if (this.checkArr.length == 0) {
+ this.joinVideo = {}
+@import '~@assets/less/common.less';
@@ -24,11 +24,37 @@
</style>
<template>
<a-card :body-style="{ padding: '24px 32px' }" :bordered="false" class="group-creat">
- <a-button type="primary" @click="visible = true">
+ <a-row class="image-list-heading vm-panel">
+ <a-col :span="24" style="display:flex">
+ <Treeselect :appId.sync="appId" :multiple="false" style="margin:8px 0px" />
+ <a-button type="primary" style="margin:10px" @click="addUser">搜索</a-button>
+ <a-button type="primary" @click=";(visible = true), (populationData = {}), (active = 'add')" :disabled="!appId">
创建模板
</a-button>
- <a-modal v-model="visible" title="广告组创建信息" :width="900">
- <targeted-population ref="population" :populationData.sync="populationData" v-if="visible"></targeted-population>
+ <a-row style="margin-top:15px">
+ <a-table size="middle" :columns="columns" :dataSource="dataList" bordered :pagination="ipagination">
+ <a @click="handleEdit(record)">编辑</a>
+ <a-popconfirm title="确定删除吗?" @confirm="() => handleDelete(record.id)">
+ <a>删除</a>
+ </a-popconfirm>
+ <a-modal v-model="visible" title="广告组创建信息" :width="900" v-if="visible">
+ label="模板名称"
+ :labelCol="{ lg: { span: 7 }, sm: { span: 7 } }"
+ :wrapperCol="{ lg: { span: 10 }, sm: { span: 17 } }"
+ <a-input placeholder="请输入模板名称" v-model="name" style="width:100%;position:relative;" />
+ <targeted-population ref="population" :populationData.sync="populationData"></targeted-population>
<template slot="footer">
<a-button key="submit" type="primary" @click="handleSubmit">
确定
@@ -39,122 +65,162 @@
-import { getAction, postAction } from '@/api/manage'
+import { getAction, postAction, deleteAction, putAction } from '@/api/manage'
import jq from 'jquery'
+import Treeselect from '@/views/modules/Statistics/components/Treeselect.vue'
import targetedPopulation from '@/views/modules/kuaishouapp/account/stepForm/stepModule/targetedPopulation.vue'
name: 'new-mould',
- targetedPopulation
+ targetedPopulation,
+ Treeselect
- populationData: {
- platform_os: '1',
- is_open: '0',
- gender: '1',
- network: '1',
- interest_video: [2, 3],
- ages_range: ['12', '41'],
- device_brand: ['2', '9'],
- device_price: ['5', '9'],
- fans_star: [2, 3, 4, 5],
- app_interest: [3, 4],
- android_osv: '3',
- business_interest_type: '2',
- business_interest: [34328, 34330],
- no_age_break: 0,
- no_gender_break: 0,
- no_area_break: 0,
- region: [
- 11,
- 12,
- 13,
- 14,
- 15,
- 21,
- 22,
- 23,
- 31,
- 32,
- 33,
- 34,
- 35,
- 36,
- 37,
- 41,
- 42,
- 43,
- 44,
- 45,
- 46,
- 50,
- 51,
- 52,
- 53,
- 54,
- 61,
- 62,
- 63,
- 64,
- 65,
- 71,
- 81,
- 82
- ],
- allForm: {
- regionType: 'limit',
- { label: '北京', value: 11 },
- { label: '天津', value: 12 },
- { label: '河北', value: 13 },
- { label: '山西', value: 14 },
- { label: '内蒙古', value: 15 },
- { label: '辽宁', value: 21 },
- { label: '吉林', value: 22 },
- { label: '黑龙江', value: 23 },
- { label: '上海', value: 31 },
- { label: '江苏', value: 32 },
- { label: '浙江', value: 33 },
- { label: '安徽', value: 34 },
- { label: '福建', value: 35 },
- { label: '江西', value: 36 },
- { label: '山东', value: 37 },
- { label: '河南', value: 41 },
- { label: '湖北', value: 42 },
- { label: '湖南', value: 43 },
- { label: '广东', value: 44 },
- { label: '广西', value: 45 },
- { label: '海南', value: 46 },
- { label: '重庆', value: 50 },
- { label: '四川', value: 51 },
- { label: '贵州', value: 52 },
- { label: '云南', value: 53 },
- { label: '西藏', value: 54 },
- { label: '陕西', value: 61 },
- { label: '甘肃', value: 62 },
- { label: '青海', value: 63 },
- { label: '宁夏', value: 64 },
- { label: '新疆', value: 65 },
- { label: '台湾', value: 71 },
- { label: '香港', value: 81 },
- { label: '澳门', value: 82 }
- ageType: 'ageLimit',
- ages_range: [],
- age: [],
- device: '1',
- price: '1',
- appType: '1',
- fansStar: '1',
- interestVideo: '1'
+ dataList: [],
+ name: '',
+ title: '模板名称',
+ dataIndex: 'templateName',
+ scopedSlots: { customRender: 'templateName' }
+ title: '创建时间',
+ dataIndex: 'createTime',
+ scopedSlots: { customRender: 'createTime' }
+ appId: '',
+ populationData: {
+ // platform_os: '1',
+ // is_open: '0',
+ // gender: '1',
+ // network: '1',
+ // interest_video: [2, 3],
+ // ages_range: ['12', '41'],
+ // device_brand: ['2', '9'],
+ // device_price: ['5', '9'],
+ // fans_star: [2, 3, 4, 5],
+ // app_interest: [3, 4],
+ // android_osv: '4',
+ // business_interest_type: '2',
+ // business_interest: [34328, 34330],
+ // no_age_break: 0,
+ // no_gender_break: 0,
+ // no_area_break: 0,
+ // region: [
+ // 11,
+ // 12,
+ // 13,
+ // 14,
+ // 15,
+ // 21,
+ // 22,
+ // 23,
+ // 31,
+ // 32,
+ // 33,
+ // 34,
+ // 35,
+ // 36,
+ // 37,
+ // 41,
+ // 42,
+ // 43,
+ // 44,
+ // 45,
+ // 46,
+ // 50,
+ // 51,
+ // 52,
+ // 53,
+ // 54,
+ // 61,
+ // 62,
+ // 63,
+ // 64,
+ // 65,
+ // 71,
+ // 81,
+ // 82
+ // ],
+ // allForm: {
+ // regionType: 'limit',
+ // { label: '北京', value: 11 },
+ // { label: '天津', value: 12 },
+ // { label: '河北', value: 13 },
+ // { label: '山西', value: 14 },
+ // { label: '内蒙古', value: 15 },
+ // { label: '辽宁', value: 21 },
+ // { label: '吉林', value: 22 },
+ // { label: '黑龙江', value: 23 },
+ // { label: '上海', value: 31 },
+ // { label: '江苏', value: 32 },
+ // { label: '浙江', value: 33 },
+ // { label: '安徽', value: 34 },
+ // { label: '福建', value: 35 },
+ // { label: '江西', value: 36 },
+ // { label: '山东', value: 37 },
+ // { label: '河南', value: 41 },
+ // { label: '湖北', value: 42 },
+ // { label: '湖南', value: 43 },
+ // { label: '广东', value: 44 },
+ // { label: '广西', value: 45 },
+ // { label: '海南', value: 46 },
+ // { label: '重庆', value: 50 },
+ // { label: '四川', value: 51 },
+ // { label: '贵州', value: 52 },
+ // { label: '云南', value: 53 },
+ // { label: '西藏', value: 54 },
+ // { label: '陕西', value: 61 },
+ // { label: '甘肃', value: 62 },
+ // { label: '青海', value: 63 },
+ // { label: '宁夏', value: 64 },
+ // { label: '新疆', value: 65 },
+ // { label: '台湾', value: 71 },
+ // { label: '香港', value: 81 },
+ // { label: '澳门', value: 82 }
+ // ageType: 'ageLimit',
+ // ages_range: [],
+ // age: [],
+ // device: '1',
+ // price: '1',
+ // appType: '1',
+ // fansStar: '1',
+ // interestVideo: '1'
- visible: false
+ active: 'add',
+ editId: '',
computed: {},
@@ -164,12 +230,83 @@ export default {
// this.$refs.population.handleSubmit()
e.preventDefault()
this.$refs.population.handleSubmit()
- console.log(JSON.stringify(this.populationData))
+ var data = this.populationData
+ console.log(JSON.stringify(data))
+ if (this.active == 'add') {
+ postAction('/kuaishou/batch/addDirectionalTemplate', {
+ accountId: this.appId,
+ templateName: this.name,
+ templateContent: JSON.stringify(this.populationData)
+ this.visible = false
+ this.populationData = {}
+ this.name = ''
+ } else if (this.active == 'edit') {
+ putAction('/kuaishou/batch/editDirectionalTemplate', {
+ id: this.editId,
getData(className) {
return this.form.getFieldValue(className)
+ handleEdit(item) {
+ this.active = 'edit'
+ this.editId = item.id
+ this.name = item.templateName
+ this.populationData = JSON.parse(item.templateContent)
+ this.visible = true
+ handleDelete(id) {
+ deleteAction('/kuaishou/batch/deleteeditDirectionalTemplate', { id: id }).then(res => {
+ this.$message.success('删除成功')
+ addUser() {
+ this.dataList = []
+ if (this.appId) {
+ getAction('/kuaishou/batch/getDirectionalTemplate', params).then(res => {
+ this.dataList = res.result.map((item, index) => {
+ this.ipagination.total = res.result.length
+ this.$message.error('请选择账户')
- mounted: function() {}
+ // /kuaishou/batch/getDirectionalTemplate
@@ -7,6 +7,12 @@
.creative-name .ant-table td {
white-space: nowrap;
+.else-label .ant-form-item-label label::after {
+ content: '';
+ top: -0.5px;
+ margin: 0 8px 0 2px;
<div class="creative-name">
@@ -37,6 +43,9 @@
+ <a @click="editOriginality(record)">编辑</a>
<img slot="coverUrl" slot-scope="text" :src="text" alt="" style="width:100px" />
@@ -45,6 +54,97 @@
</a-tabs>
</a-row>
+ <a-modal v-model="visible" title="修改" @ok="handleOk" :width="800">
+ <a-form @submit="handleSubmit" :form="form" style="margin-top:20px" :hideRequiredMark="true">
+ label="素材类型"
+ :labelCol="{ lg: { span: 4 }, sm: { span: 4 } }"
+ :wrapperCol="{ lg: { span: 18 }, sm: { span: 17 } }"
+ <a-radio-group buttonStyle="solid" v-decorator="['creativeMaterialType', { initialValue: 1 }]">
+ <a-radio-button :value="1">竖版视频</a-radio-button>
+ <a-radio-button :value="2">横版视频</a-radio-button>
+ label=" "
+ class="else-label"
+ <a @click="getVideoList('video')">选择视频</a>
+ <br />
+ <video :src="video.url" controls="controls" style="width:25%" v-if="video.url"></video>
+ <a @click="getVideoList('image')">选择封面</a>
+ <img :src="image.coverUrl" style="width:25%;" v-if="image.coverUrl" />
+ label="创意标题"
+ <a-input
+ class="rending"
+ v-decorator="['creativeName', { rules: [{ required: true, message: '请输入创意标题' }] }]"
+ ></a-input>
+ label="广告语"
+ <a-textarea
+ placeholder="请输入广告语"
+ v-decorator="['description', { rules: [{ required: true, message: '请输入广告语' }] }]"
+ :autosize="{ minRows: 2, maxRows: 6 }"
+ ></a-textarea>
+ label="行动号召"
+ v-decorator="['actionBarText', { rules: [{ required: true, message: '行动号召按钮文案' }] }]"
+ placeholder="选择行动号召按钮文案"
+ <a-select-option v-for="appModel in appList" :key="appModel.id" :value="appModel.actionBarText">
+ {{ appModel.actionBarText }}
+ label="检测链接"
+ :labelCol="{ lg: { span: 4 }, sm: { span: 2 } }"
+ :wrapperCol="{ lg: { span: 18 }, sm: { span: 18 } }"
+ v-decorator="[
+ 'clickTrackUrl',
+ rules: [{ required: true, message: '请输入第三方检测链接' }]
+ ]"
+ placeholder="请输入第三方检测链接"
+ <checkMatemal ref="check" @showVideo="showData"></checkMatemal>
</div>
@@ -55,10 +155,13 @@ import moment from 'moment'
import countTo from 'vue-count-to'
import { deleteAction, getAction, postAction } from '@/api/manage'
+import checkMatemal from './editMatemal'
+import pick from 'lodash.pick'
// import lifting from './components/lifting'
const columns = [
width: 100,
@@ -70,6 +173,13 @@ const columns = [
align: 'center'
title: '封面',
dataIndex: 'coverUrl',
scopedSlots: { customRender: 'coverUrl' },
@@ -100,17 +210,23 @@ export default {
ACol,
ARow,
- countTo
+ countTo,
+ checkMatemal
+ visibleTwo: false,
+ image: {},
+ video: {},
many: 1200,
manyTwo: null,
columns,
dataList: [],
@@ -142,7 +258,10 @@ export default {
titleKey: null,
selectedRowKeys: [],
selectedRowKeysValue: [],
- allType: '1'
+ allType: '1',
+ appList: [],
+ creativeId: ''
@@ -173,6 +292,88 @@ export default {
+ editOriginality(item) {
+ this.creativeId = item.creativeId
+ getAction('/kuaishou/batch/getActionBarText', { campaignId: localStorage.getItem('campaignId') }).then(res => {
+ this.appList = res.result
+ getAction('/kuaishou/batch/getVideoDetail', {
+ accountId: localStorage.getItem('accountId'),
+ photoId: item.photoId
+ this.video.url = res.result.url
+ this.video.photoId = res.result.photoId
+ this.image.coverUrl = item.coverUrl
+ this.image.imageToken = item.imageToken
+ this.form.setFieldsValue(
+ pick(item, ['clickTrackUrl', 'actionBarText', 'creativeName', 'description', 'creativeMaterialType'])
+ )
+ this.handleSubmit()
+ handleSubmit() {
+ var params = {
+ photoId: this.video.photoId,
+ imageToken: this.image.imageToken,
+ ...values,
+ creativeId: this.creativeId,
+ accountId: localStorage.getItem('accountId')
+ console.log(params)
+ postAction('/kuaishou/batch/updateCreative', params).then(res => {
+ this.getDataList(localStorage.getItem('originalityKey'))
+ getVideoList(type) {
+ if (type == 'video') {
+ this.$refs.check.showCheck(this.getData('creativeMaterialType'), '/kuaishou/batch/getVideoList', type)
+ this.$refs.check.showCheck(this.getData('creativeMaterialType'), '/kuaishou/batch/getImageList', type)
+ showData(item, type) {
+ this.video = {}
+ console.log(item, 'v')
+ this.video.url = item.url
+ this.video.photoId = item.photoId
+ console.log(item, 'i')
+ this.image = {}
+ this.image.coverUrl = item.url
+ getData(className) {
+ return this.form.getFieldValue(className)
...mapGetters(['nickname', 'avatar', 'userInfo']),
onChangeSwitch(item) {
@@ -54,65 +54,6 @@
></a-input
>元
- <!-- <a-form-item
- v-if="showApp"
- label="目标应用"
- :labelCol="{ lg: { span: 7 }, sm: { span: 7 } }"
- :wrapperCol="{ lg: { span: 10 }, sm: { span: 17 } }"
- >
- <a-select
- v-model="appId"
- showSearch
- allowClear
- placeholder="选择应用目标"
- optionFilterProp="children"
- style="width: 600px"
- @focus="handleFocus"
- @blur="handleBlur"
- @change="handleChange"
- :filterOption="filterOption"
- <a-select-option v-for="appModel in appList" :key="appModel.id" :value="appModel.id"
- >{{ appModel.appName }}   {{ appModel.appType }}  
- {{ appModel.appVersion }}</a-select-option
- </a-select>
- </a-form-item>
- <a-form-item
- v-if="showUrlType"
- label="转化类型"
- <a-radio-group v-model="urlType">
- <a-radio-button value="1">淘宝商品短链</a-radio-button>
- <a-radio-button value="2">淘宝商品</a-radio-button>
- </a-radio-group>
- v-if="showChannelType"
- <a-radio-group v-model="channelType">
- <a-radio-button value="1">填写链接</a-radio-button>
- <a-radio-button value="2" disabled="disabled">落地页工具</a-radio-button>
- v-if="showRedirect"
- label="链接地址"
- <a-input v-model="redirectUrl"></a-input>
- </a-form-item> -->
<a-form-item :wrapperCol="{ span: 24 }" style="text-align: center">
<a-button htmlType="submit" type="primary" :loading="loading">下一步</a-button>
<!-- <a-button style="margin-left: 8px">保存</a-button> -->
@@ -182,7 +123,7 @@ export default {
let params = {}
params.type = this.type
// params.campaignBudget = this.campaignBudget
- params.dayBudget = this.campaignBudget == 'UNLIMITED' ? 0 : values.dayBudget
+ params.dayBudget = this.campaignBudget == 'UNLIMITED' ? 0 : values.dayBudget * 1000
params.campaignName = this.campaignName
params.accountId = localStorage.getItem('accountId')
console.log(params)
@@ -17,7 +17,7 @@
:labelCol="{ lg: { span: 2 }, sm: { span: 4 } }"
:wrapperCol="{ lg: { span: 18 }, sm: { span: 17 } }"
- <a-radio-group buttonStyle="solid" v-decorator="['creative_material_type', { initialValue: '1' }]">
+ <a-radio-group buttonStyle="solid" v-decorator="['creativeMaterialType', { initialValue: '1' }]">
<a-radio-button value="1">竖版视频</a-radio-button>
<a-radio-button value="2">横版视频</a-radio-button>
</a-radio-group>
@@ -86,7 +86,7 @@
</a-radio-group> -->
<a-select
- v-decorator="['action_bar_text', { rules: [{ required: true, message: '行动号召按钮文案' }] }]"
showSearch
allowClear
placeholder="选择行动号召按钮文案"
@@ -105,10 +105,10 @@
<a-input
v-decorator="[
- 'click_track_url',
rules: [
- { required: pane.bid_type == 6, message: '请输入第三方检测链接' },
+ { required: pane.bidType == 6, message: '请输入第三方检测链接' },
{ validator: handleConfirmValue }
]
@@ -129,14 +129,14 @@
创建成功:{{ allForm.success.length }}条
<div style="margin-top:20px">
<p v-for="(item, index) of allForm.success" :key="index">
- <span>名称:{{ item.creative_name }}</span>
+ <span>名称:{{ item.creativeName }}</span>
</p>
<br />
创建失败:{{ allForm.fail.length }}条
<p v-for="(item, index) of allForm.fail" :key="index">
- <span>名称:{{ item.creative_name }}</span
+ <span>名称:{{ item.creativeName }}</span
><br />
<span>错误信息:{{ item.failMessage }}</span>
@@ -210,7 +210,7 @@ export default {
getVideoList(type, index, item, bestIndex) {
if (type == 'video') {
this.$refs.check.showCheck(
- this.getData('creative_material_type'),
+ this.getData('creativeMaterialType'),
'/kuaishou/batch/getVideoList',
item.videoList,
type,
@@ -218,7 +218,7 @@ export default {
} else {
'/kuaishou/batch/getImageList',
item.imageList,
@@ -279,10 +279,10 @@ export default {
var dataJson = this.pans[index].list.map(item => {
description: item.description,
- image_tokens: item.imageList.map((ele, index) => {
+ imageTokens: item.imageList.map((ele, index) => {
return { image: ele.imageToken, name: index + 1 + '-' + item.name }
- photo_id: item.videoList.photoId
+ photoId: item.videoList.photoId
var params = { dataJson, ...values, unitId: this.pansKey, accountId: localStorage.getItem('accountId') }
@@ -315,7 +315,7 @@ export default {
videoList: '',
imageList: [],
name:
- this.getData('creative_material_type') == '1'
+ this.getData('creativeMaterialType') == '1'
? '自定义创意_竖版视频_' +
Math.random()
.toString(36)
@@ -325,8 +325,8 @@ export default {
.substr(2, 4),
description: '',
- creative_material_type: '1',
- action_bar_text: ''
+ creativeMaterialType: '1',
+ actionBarText: ''
deleteCreative(bestIndex, index) {
@@ -0,0 +1,168 @@
+ <a-form-item label="jobId">
+ <a-input placeholder="请输入jobId" v-model="queryParam.jobId"></a-input>
+ <a-form-item label="videoId">
+ <a-input placeholder="请输入videoId" v-model="queryParam.videoId"></a-input>
+ <template v-if="toggleSearchStatus">
+ <a-form-item label="status">
+ <a-input placeholder="请输入status" v-model="queryParam.status"></a-input>
+ <a @click="handleToggleSearch" style="margin-left: 8px">
+ {{ toggleSearchStatus ? '收起' : '展开' }}
+ <a-icon :type="toggleSearchStatus ? 'up' : 'down'"/>
+ </a>
+ <a-button type="primary" icon="download" @click="handleExportXls('视频合成任务')">导出</a-button>
+ <a-dropdown v-if="selectedRowKeys.length > 0">
+ <a-menu slot="overlay">
+ <a-menu-item key="1" @click="batchDel"><a-icon type="delete"/>删除</a-menu-item>
+ </a-menu>
+ <a-button style="margin-left: 8px"> 批量操作 <a-icon type="down" /></a-button>
+ </a-dropdown>
+ <div class="ant-alert ant-alert-info" style="margin-bottom: 16px;">
+ <i class="anticon anticon-info-circle ant-alert-icon"></i> 已选择 <a style="font-weight: 600">{{ selectedRowKeys.length }}</a>项
+ <a style="margin-left: 24px" @click="onClearSelected">清空</a>
+ :rowSelection="{selectedRowKeys: selectedRowKeys, onChange: onSelectChange}"
+ <a-dropdown>
+ <a class="ant-dropdown-link">更多 <a-icon type="down" /></a>
+ <a-menu-item>
+ </a-menu-item>
+ <videoMergeTask-modal ref="modalForm" @ok="modalFormOk"></videoMergeTask-modal>
+ import VideoMergeTaskModal from './modules/VideoMergeTaskModal'
+ name: "VideoMergeTaskList",
+ VideoMergeTaskModal
+ description: '视频合成任务管理页面',
+ width:60,
+ customRender:function (t,r,index) {
+ return parseInt(index)+1;
+ title: 'jobId',
+ dataIndex: 'jobId'
+ title: 'videoId',
+ dataIndex: 'videoId'
+ title: 'status',
+ dataIndex: 'status'
+ scopedSlots: { customRender: 'action' },
+ list: "/ctop/videoMergeTask/list",
+ delete: "/ctop/videoMergeTask/delete",
+ deleteBatch: "/ctop/videoMergeTask/deleteBatch",
+ exportXlsUrl: "ctop/videoMergeTask/exportXls",
+ importExcelUrl: "ctop/videoMergeTask/importExcel",
@@ -0,0 +1,156 @@
+ <a-form-item label="partId">
+ <a-input placeholder="请输入partId" v-model="queryParam.partId"></a-input>
+ <a-button type="primary" icon="download" @click="handleExportXls('视频片段')">导出</a-button>
+ <videoPart-modal ref="modalForm" @ok="modalFormOk"></videoPart-modal>
+ import VideoPartModal from './modules/VideoPartModal'
+ name: "VideoPartList",
+ VideoPartModal
+ description: '视频片段管理页面',
+ title: 'partId',
+ dataIndex: 'partId'
+ list: "/ctop/videoPart/list",
+ delete: "/ctop/videoPart/delete",
+ deleteBatch: "/ctop/videoPart/deleteBatch",
+ exportXlsUrl: "ctop/videoPart/exportXls",
+ importExcelUrl: "ctop/videoPart/importExcel",
@@ -0,0 +1,188 @@
+ <a-form-item label="userId">
+ <a-input placeholder="请输入userId" v-model="queryParam.userId"></a-input>
+ <a-form-item label="videoUrl">
+ <a-input placeholder="请输入videoUrl" v-model="queryParam.videoUrl"></a-input>
+ <a-button type="primary" icon="download" @click="handleExportXls('水印任务表')">导出</a-button>
+ <videoWatermarkTask-modal ref="modalForm" @ok="modalFormOk"></videoWatermarkTask-modal>
+ import VideoWatermarkTaskModal from './modules/VideoWatermarkTaskModal'
+ name: "VideoWatermarkTaskList",
+ VideoWatermarkTaskModal
+ description: '水印任务表管理页面',
+ title: 'userId',
+ dataIndex: 'userId'
+ title: 'videoUrl',
+ dataIndex: 'videoUrl'
+ list: "/ctop/videoWatermarkTask/list",
+ delete: "/ctop/videoWatermarkTask/delete",
+ deleteBatch: "/ctop/videoWatermarkTask/deleteBatch",
+ exportXlsUrl: "ctop/videoWatermarkTask/exportXls",
+ importExcelUrl: "ctop/videoWatermarkTask/importExcel",
+ <a-form-item label="name">
+ <a-input placeholder="请输入name" v-model="queryParam.name"></a-input>
+ <a-form-item label="width">
+ <a-input placeholder="请输入width" v-model="queryParam.width"></a-input>
+ <a-form-item label="height">
+ <a-input placeholder="请输入height" v-model="queryParam.height"></a-input>
+ <a-form-item label="templateId">
+ <a-input placeholder="请输入templateId" v-model="queryParam.templateId"></a-input>
+ <a-form-item label="templatePath">
+ <a-input placeholder="请输入templatePath" v-model="queryParam.templatePath"></a-input>
+ <a-button type="primary" icon="download" @click="handleExportXls('水印模板')">导出</a-button>
+ <videoWatermarkTemplate-modal ref="modalForm" @ok="modalFormOk"></videoWatermarkTemplate-modal>
+ import VideoWatermarkTemplateModal from './modules/VideoWatermarkTemplateModal'
+ name: "VideoWatermarkTemplateList",
+ VideoWatermarkTemplateModal
+ description: '水印模板管理页面',
+ title: 'name',
+ title: 'width',
+ dataIndex: 'width'
+ title: 'height',
+ dataIndex: 'height'
+ title: 'templateId',
+ dataIndex: 'templateId'
+ title: 'templatePath',
+ dataIndex: 'templatePath'
+ list: "/ctop/videoWatermarkTemplate/list",
+ delete: "/ctop/videoWatermarkTemplate/delete",
+ deleteBatch: "/ctop/videoWatermarkTemplate/deleteBatch",
+ exportXlsUrl: "ctop/videoWatermarkTemplate/exportXls",
+ importExcelUrl: "ctop/videoWatermarkTemplate/importExcel",
@@ -146,8 +146,9 @@ a {
<div class="table-page-search-wrapper">
<a-form layout="inline">
<a-row :gutter="24">
- <a-col :md="6" :sm="8">
- <a-form-item label="项目名称">
+ <a-col :md="8" :sm="8">
+ <selectTable :projectId.sync="queryParam.projectId"></selectTable>
+ <!-- <a-form-item label="项目名称">
placeholder="请输入项目名称"
@@ -157,10 +158,12 @@ a {
@change="getList"
<a-select-option :value="item.projectId" v-for="item of dataElse" :key="item.id">
- {{ item.projectName }}
+ {{ item.projectName }} {{
+ item.mediaId == '1' ? '头条' : '快手'
+ }} {{ item.advertiserName }}
</a-select-option>
</a-select>
+ </a-form-item> -->
</a-col>
<!-- <a-col :md="6" :sm="8">
<a-form-item label="剪辑">
@@ -177,12 +180,12 @@ a {
<a-input placeholder="请输入拍摄" v-model="queryParam.responsible"></a-input>
</a-col> -->
<a-form-item label="时间选择">
<a-date-picker v-model="queryParam.createTime" format="YYYY-MM-DD" style="width:100%" />
<span style="float: left;overflow: hidden;" class="table-page-search-submitButtons">
<a-button type="primary" @click="searchQuery" icon="search">查询</a-button>
<a-button type="primary" @click="searchRe" icon="reload" style="margin-left: 8px">重置</a-button>
@@ -375,7 +378,7 @@ a {
</a-tab-pane>
- <a-modal title="添加素材" v-model="visible" @ok="handleOk" @cancel="close" :maskClosable="false">
+ <a-modal title="添加素材" v-model="visible" @ok="handleOk" @cancel="close" :maskClosable="false" :width="800">
<a-form-item :label-col="labelCol" :wrapper-col="wrapperCol" label="项目选择">
@@ -386,11 +389,19 @@ a {
@change="getProjectId"
- <a-form-item :label-col="labelCol" :wrapper-col="wrapperCol" label="图片素材上传" class="add-image-material">
+ label="图片素材上传"
+ class="add-image-material"
+ v-if="getData('projectId')"
<upload-to-ali
style="width:160%"
v-model="urlList.url"
@@ -610,6 +621,8 @@ import { getAction, postAction, postFile, downFile, downFilePost, deleteAction }
+import selectTable from '@/views/modules/Statistics/components/selecTable.vue'
import BMF from 'browser-md5-file'
import accountCheck from './accountCheck'
@@ -619,7 +632,8 @@ export default {
JEllipsis,
UploadToAli,
- accountCheck
+ accountCheck,
+ selectTable
@@ -744,6 +758,11 @@ export default {
this.active = localStorage.getItem('key') ? localStorage.getItem('key') : '0'
this.loadData()
+ 'queryParam.projectId': function(n, o) {
+ if (n != '') {
+ this.getList(n)
@@ -910,15 +929,20 @@ export default {
searchRe() {
this.queryParam.projectId = ''
- this.queryParam.createTime = ''
+ if (this.queryParam.createTime) {
+ this.queryParam.createTime = ''
getList(value) {
- this.mediaId = this.dataElse.filter(item => {
- if (value == item.projectId) {
- return item
- })[0].mediaId
+ if (value) {
+ this.mediaId = this.dataElse.filter(item => {
+ if (value == item.projectId) {
+ return item
+ })[0].mediaId
onChangeCheck(checkedList) {
@@ -1163,7 +1187,7 @@ export default {
// that.urlList.name.push(file[0].name)
// that.urlList.md5.push(md5)
- fileCheck({ code: md5 }).then(res => {
+ fileCheck({ code: md5, projectId: that.getData('projectId') }).then(res => {
that.$message.error('此素材已经上传')
reject()
@@ -1176,6 +1200,9 @@ export default {
fileWater(file) {
var bmf = new BMF()
var that = this
@@ -0,0 +1,139 @@
+ label="jobId">
+ <a-input placeholder="请输入jobId" v-decorator="['jobId', validatorRules.jobId ]" />
+ label="videoId">
+ <a-input placeholder="请输入videoId" v-decorator="['videoId', validatorRules.videoId ]" />
+ label="status">
+ <a-input placeholder="请输入status" v-decorator="['status', validatorRules.status ]" />
+ name: "VideoMergeTaskModal",
+ jobId:{rules: [{ required: true, message: '请输入jobId!' }]},
+ videoId:{rules: [{ required: true, message: '请输入videoId!' }]},
+ status:{rules: [{ required: true, message: '请输入status!' }]},
+ add: "/ctop/videoMergeTask/add",
+ edit: "/ctop/videoMergeTask/edit",
+ this.form.setFieldsValue(pick(this.model,'jobId','videoId','status'))
@@ -0,0 +1,132 @@
+ label="partId">
+ <a-input placeholder="请输入partId" v-decorator="['partId', validatorRules.partId ]" />
+ name: "VideoPartModal",
+ partId:{rules: [{ required: true, message: '请输入partId!' }]},
+ add: "/ctop/videoPart/add",
+ edit: "/ctop/videoPart/edit",
+ this.form.setFieldsValue(pick(this.model,'videoId','partId'))
@@ -0,0 +1,151 @@
+ label="userId">
+ <a-input placeholder="请输入userId" v-decorator="['userId', validatorRules.userId ]" />
+ <a-input placeholder="请输入videoId" v-decorator="['videoId', {}]" />
+ label="videoUrl">
+ <a-input placeholder="请输入videoUrl" v-decorator="['videoUrl', {}]" />
+ name: "VideoWatermarkTaskModal",
+ userId:{rules: [{ required: true, message: '请输入userId!' }]},
+ add: "/ctop/videoWatermarkTask/add",
+ edit: "/ctop/videoWatermarkTask/edit",
+ this.form.setFieldsValue(pick(this.model,'userId','jobId','videoId','videoUrl','status'))
@@ -0,0 +1,148 @@
+ label="name">
+ <a-input placeholder="请输入name" v-decorator="['name', {}]" />
+ label="width">
+ <a-input-number v-decorator="[ 'width', {}]" />
+ label="height">
+ <a-input-number v-decorator="[ 'height', {}]" />
+ label="templateId">
+ <a-input placeholder="请输入templateId" v-decorator="['templateId', {}]" />
+ label="templatePath">
+ <a-input placeholder="请输入templatePath" v-decorator="['templatePath', {}]" />
+ name: "VideoWatermarkTemplateModal",
+ add: "/ctop/videoWatermarkTemplate/add",
+ edit: "/ctop/videoWatermarkTemplate/edit",
+ this.form.setFieldsValue(pick(this.model,'name','width','height','templateId','templatePath'))
@@ -143,9 +143,10 @@ a {
+ <!-- <a-form-item label="项目名称"> -->
optionFilterProp="children"
@@ -154,32 +155,19 @@ a {
+ <!-- </a-form-item> -->
- <!-- <a-col :md="6" :sm="8">
- <a-form-item label="剪辑">
- <a-input placeholder="请输入剪辑者名称" v-model="queryParam.advertiserId"></a-input>
- </a-col>
- <a-form-item label="编导">
- <a-input placeholder="请输入编导" v-model="queryParam.responsible"></a-input>
- <a-form-item label="拍摄">
- <a-input placeholder="请输入拍摄" v-model="queryParam.responsible"></a-input>
- </a-col> -->
@@ -404,7 +392,7 @@ a {
- <a-modal title="添加素材" v-model="visible" :maskClosable="false">
+ <a-modal title="添加素材" v-model="visible" :maskClosable="false" :width="800">
<a-button key="back" @click="close">取消</a-button>
<a-button key="submit" type="primary" :disabled="!confirmLoading" @click="handleOk">
@@ -413,19 +401,25 @@ a {
+ <!-- <selectTable :projectId.sync="projectId" /> -->
'projectId', // 给表单赋值或拉取表单时,该input对应的key
{ rules: [{ required: true, message: '请选择项目!' }] }
]"
- <a-form-item :label-col="labelCol" :wrapper-col="wrapperCol" label="视频素材上传">
+ <a-form-item :label-col="labelCol" :wrapper-col="wrapperCol" label="视频素材上传" v-if="getData('projectId')">
:customDomain="customDomain"
@@ -522,7 +516,7 @@ a {
:label-col="labelCol"
:wrapper-col="{
xs: { span: 24 },
- sm: { span: 18 }
}"
label="描述"
@@ -728,6 +722,8 @@ import qs from 'qs'
import { stopOtherVideo, closeAllVideoFun } from '@/utils/videoControl'
@@ -737,11 +733,13 @@ export default {
inputVisible: false,
inputValue: '',
labelCol: {
@@ -873,9 +871,17 @@ export default {
deleteData(id) {
deleteAction('/ctop/materialInfo/delete', { id: id }).then(res => {
if (res.success) {
@@ -970,15 +976,19 @@ export default {
- this.loadData()
+ this.loadData(1)
@@ -1250,7 +1260,7 @@ export default {
bmf.md5(file[0], (err, md5) => {
that.urlList.name = file[0].name
that.urlList.md5 = md5
that.repeat = true
@@ -0,0 +1,388 @@
+ <a-col :md="6" :sm="24">
+ <a-form-item label="表名">
+ <a-input placeholder="请输入表名" v-model="queryParam.tableName"></a-input>
+ <a-button @click="doCgformButton" type="primary" icon="highlight" style="margin-left:8px">自定义按钮</a-button>
+ <a-button @click="doEnhanceJs" type="primary" icon="strikethrough" style="margin-left:8px">JS增强</a-button>
+ <a-button @click="doEnhanceSql" type="primary" icon="filter" style="margin-left:8px">SQL增强</a-button>
+ <a-button @click="doEnhanceJava" type="primary" icon="tool" style="margin-left:8px">Java增强</a-button>
+ <a-menu-item key="1" @click="batchDel">
+ <a-icon type="delete"/>
+ 删除
+ <a-button style="margin-left: 8px"> 批量操作
+ <a-icon type="down"/>
+ </a-button>
+ <i class="anticon anticon-info-circle ant-alert-icon"></i>
+ 已选择
+ <a style="font-weight: 600">{{ selectedRowKeys.length }}</a>
+ 项
+ <template slot="action" slot-scope="text, record">
+ <a-divider type="vertical"/>
+ <a class="ant-dropdown-link">更多
+ <a @click="goPageOnline(record)">功能测试</a>
+ <a @click="handleOnlineUrlShow(record)">配置地址</a>
+ <a @click="handleRemoveRecord(record.id)">移除</a>
+ <template slot="dbsync" slot-scope="text">
+ <span v-if="text==='Y'" style="color:limegreen">已同步</span>
+ <span v-if="text==='N'" style="color:red">未同步</span>
+ <onl-cgform-head-modal ref="modalForm" @ok="modalFormOk" :action-button="false"></onl-cgform-head-modal>
+ <!-- 提示online报表链接 -->
+ :title="onlineUrlTitle"
+ :visible="onlineUrlVisible"
+ @cancel="handleOnlineUrlClose">
+ <a-button @click="handleOnlineUrlClose">关闭</a-button>
+ <a-button type="primary" class="copy-this-text" :data-clipboard-text="onlineUrl" @click="onCopyUrl">复制</a-button>
+ <p>{{ onlineUrl }}</p>
+ <enhance-js ref="ehjs"></enhance-js>
+ <enhance-sql ref="ehsql"></enhance-sql>
+ <enhance-java ref="ehjava"></enhance-java>
+ <trans-db2-online ref="transd2o" @ok="transOk"></trans-db2-online>
+ <onl-cgform-button-list ref="btnList"></onl-cgform-button-list>
+ import { deleteAction, postAction,getAction } from '@/api/manage'
+ import Clipboard from 'clipboard'
+ import { filterObj } from '@/utils/util';
+ name: 'OnlCgformHeadList',
+ description: 'Online表单视图',
+ key: 'rowIndex',
+ width: 60,
+ customRender: function(t, r, index) {
+ return parseInt(index) + 1
+ title: '视图表名',
+ dataIndex: 'tableName'
+ title: '视图表描述',
+ dataIndex: 'tableTxt'
+ title: '原表版本',
+ dataIndex: 'tableVersion'
+ title: '视图版本',
+ dataIndex: 'copyVersion'
+ list: '/online/cgform/head/list',
+ delete: '/online/cgform/head/delete',
+ deleteBatch: '/online/cgform/head/deleteBatch',
+ removeRecord: '/online/cgform/head/removeRecord',
+ tableTypeDictOptions: [],
+ sexDictOptions: [],
+ syncModalVisible: false,
+ syncFormId: '',
+ synMethod: 'normal',
+ syncLoading: false,
+ onlineUrlTitle: '',
+ onlineUrlVisible: false,
+ onlineUrl: '',
+ selectedRows: [],
+ physicId:""
+ '$route'() {
+ getQueryParams() {
+ //获取查询条件
+ var param = Object.assign({}, this.queryParam, this.isorter ,this.filters);
+ param.field = this.getQueryField();
+ param.pageNo = this.ipagination.current;
+ param.pageSize = this.ipagination.pageSize;
+ param.copyType = 1;
+ param.physicId = this.physicId;
+ return filterObj(param);
+ loadData(arg) {
+ if(!this.$route.params.code){
+ this.physicId = this.$route.params.code
+ if(!this.url.list){
+ this.$message.error("请设置url.list属性!")
+ //加载数据 若传入参数1则加载第一页的内容
+ if (arg === 1) {
+ this.ipagination.current = 1;
+ var params = this.getQueryParams();//查询条件
+ this.loading = true;
+ getAction(this.url.list, params).then((res) => {
+ this.dataSource = res.result.records;
+ this.ipagination.total = res.result.total;
+ if(res.code===510){
+ this.$message.warning(res.message)
+ this.loading = false;
+ goPageOnline(rd) {
+ if(rd.isTree=='Y'){
+ this.$router.push({ path: '/online/cgformTreeList/' + rd.id })
+ this.$router.push({ path: '/online/cgformList/' + rd.id })
+ handleOnlineUrlClose() {
+ this.onlineUrlTitle = ''
+ this.onlineUrlVisible = false
+ handleOnlineUrlShow(record) {
+ if(record.isTree=='Y'){
+ this.onlineUrl = `/online/cgformTreeList/${record.id}`
+ this.onlineUrl = `/online/cgformList/${record.id}`
+ this.onlineUrlVisible = true
+ this.onlineUrlTitle = '菜单链接[' + record.tableTxt + ']'
+ handleRemoveRecord(id) {
+ let that = this
+ this.$confirm({
+ title: '确认要移除此记录?',
+ onOk() {
+ deleteAction(that.url.removeRecord, { id: id }).then((res) => {
+ that.$message.success('移除成功')
+ that.loadData()
+ that.$message.warning(res.message)
+ onCancel() {
+ doEnhanceJs() {
+ if (!this.selectedRowKeys || this.selectedRowKeys.length != 1) {
+ this.$message.warning('请先选中一条记录')
+ this.$refs.ehjs.show(this.selectedRowKeys[0])
+ doEnhanceSql() {
+ this.$refs.ehsql.show(this.selectedRowKeys[0])
+ doEnhanceJava() {
+ this.$refs.ehjava.show(this.selectedRowKeys[0])
+ doCgformButton() {
+ this.$refs.btnList.show(this.selectedRowKeys[0])
+ //this.$router.push({ path: '/online/cgformButton/' + this.selectedRowKeys[0] })
+ importOnlineForm() {
+ this.$refs.transd2o.show()
+ transOk() {
+ onSelectChange(keys, rows) {
+ this.selectedRowKeys = keys
+ this.selectedRows = rows
+ onCopyUrl(){
+ var clipboard = new Clipboard('.copy-this-text')
+ clipboard.on('success', () => {
+ clipboard.destroy()
+ this.$message.success('复制成功')
+ this.handleOnlineUrlClose()
+ clipboard.on('error', () => {
+ this.$message.error('该浏览器不支持自动复制')
+ showMyCopyInfo(id){
+ console.log("查看复制表单的信息",id)
+ copyConfig(id){
+ postAction(`${this.url.copyOnline}?code=${id}`).then(res=>{
+ this.$message.success("复制成功")
+ this.$message.error("复制失败>>"+res.message)
+<style lang="less">
+ .ant-card-body .table-operator {
+ margin-bottom: 18px;
+ .ant-table-tbody .ant-table-row td {
+ padding-top: 15px;
+ padding-bottom: 15px;
+ .anty-row-operator button {
+ margin: 0 5px
+ .ant-btn-danger {
+ background-color: #ffffff
+ .ant-modal-cust-warp {
+ height: 100%
+ .ant-modal-cust-warp .ant-modal-body {
+ height: calc(100% - 110px) !important;
+ overflow-y: auto
+ .ant-modal-cust-warp .ant-modal-content {
+ height: 90% !important;
+ overflow-y: hidden
+ .valid-error-cust{
+ .ant-select-selection{
+ border:2px solid #f5222d;
@@ -0,0 +1,478 @@
+ <a-form-item label="表类型">
+ <j-dict-select-tag dictCode="cgform_table_type" v-model="queryParam.tableType"/>
+ <a-button @click="doEnhanceSql" type="primary" icon="filter" v-has="'online:sql'" style="margin-left:8px">SQL增强</a-button>
+ <a-button @click="importOnlineForm" type="primary" icon="database" style="margin-left:8px">从数据库导入表单</a-button>
+ <a-button @click="goGenerateCode" v-has="'online:goGenerateCode'" type="primary" icon="database" style="margin-left:8px">代码生成</a-button>
+ <a-menu-item v-if="record.isDbSynch!='Y'">
+ <a @click="openSyncModal(record.id)">同步数据库</a>
+ <template v-if="record.isDbSynch=='Y' && record.tableType !== 3">
+ <a @click="copyConfig(record.id)">复制视图</a>
+ <a-menu-item v-if="record.hascopy==1">
+ <a @click="showMyCopyInfo(record.id)">配置视图</a>
+ <onl-cgform-head-modal ref="modalForm" @ok="modalFormOk"></onl-cgform-head-modal>
+ <!-- 同步数据库提示框 -->
+ :width="500"
+ :height="300"
+ title="同步数据库"
+ :visible="syncModalVisible"
+ @cancel="handleCancleDbSync"
+ style="top:5%;height: 95%;">
+ <a-button @click="handleCancleDbSync">关闭</a-button>
+ <a-button type="primary" :loading="syncLoading" @click="handleDbSync">
+ 确定
+ <a-radio-group v-model="synMethod">
+ <a-radio style="display: block;width: 30px;height: 30px" value="normal">普通同步(保留表数据)</a-radio>
+ <a-radio style="display: block;width: 30px;height: 30px" value="force">强制同步(删除表,重新生成)</a-radio>
+ <code-generator ref="cg"></code-generator>
+ import { initDictOptions, filterDictText } from '@/components/dict/JDictSelectUtil'
+ import { deleteAction, postAction } from '@/api/manage'
+ import JDictSelectTag from '../../../../components/dict/JDictSelectTag.vue'
+ JDictSelectTag,
+ description: 'Online表单开发管理页面',
+ title: '表类型',
+ dataIndex: 'tableType',
+ customRender: (text) => {
+ return filterDictText(this.tableTypeDictOptions, `${text}`)
+ title: '表名',
+ title: '表描述',
+ title: '版本',
+ title: '同步数据库状态',
+ dataIndex: 'isDbSynch',
+ scopedSlots: { customRender: 'dbsync' }
+ doDbSynch: '/online/cgform/api/doDbSynch/',
+ copyOnline: '/online/cgform/head/copyOnline'
+ selectedRows: []
+ //初始化字典 - 表类型
+ initDictOptions('cgform_table_type').then((res) => {
+ this.tableTypeDictOptions = res.result
+ doDbSynch(id) {
+ postAction(this.url.doDbSynch + id, { synMethod: '1' }).then((res) => {
+ this.$message.success(res.message)
+ param.copyType = 0;
+ handleCancleDbSync() {
+ this.syncModalVisible = false
+ handleDbSync() {
+ this.syncLoading = true
+ postAction(this.url.doDbSynch + this.syncFormId + '/' + this.synMethod).then((res) => {
+ this.syncLoading = false
+ setTimeout(()=>{
+ if(this.syncLoading){
+ this.$message.success("网络延迟,已自动刷新!")
+ },10000)
+ openSyncModal(id) {
+ this.syncModalVisible = true
+ this.syncFormId = id
+ goGenerateCode() {
+ let row = this.selectedRows[0]
+ if (!row.isDbSynch || row.isDbSynch == 'N') {
+ this.$message.warning('请先同步数据库!')
+ if (row.tableType == 3) {
+ this.$message.warning('请选中该表对应的主表生成代码')
+ this.$refs.cg.show(this.selectedRowKeys[0])
+ this.$router.push({ path: '/online/copyform/' + id })
@@ -0,0 +1,820 @@
+ <a-card :bordered="false" style="height: 100%">
+ <a-form layout="inline" @keyup.enter.native="searchByquery">
+ <a-row :gutter="24" v-if="queryInfo && queryInfo.length>0">
+ <template v-for="(item,index) in queryInfo">
+ <template v-if=" item.hidden==='1' ">
+ <a-col v-if="item.view=='datetime'" :md="12" :sm="16" :key=" 'query'+index " v-show="toggleSearchStatus">
+ <online-query-form-item :queryParam="queryParam" :item="item" :dictOptions="dictOptions"></online-query-form-item>
+ <a-col v-else :md="6" :sm="8" :key=" 'query'+index " v-show="toggleSearchStatus">
+ <template v-else>
+ <a-col v-if="item.view=='datetime'" :md="12" :sm="16" :key=" 'query'+index ">
+ <a-col v-else :md="6" :sm="8" :key=" 'query'+index ">
+ <a-button type="primary" @click="searchByquery" icon="search">查询</a-button>
+ <a-button v-if="buttonSwitch.add" @click="handleAdd" type="primary" icon="plus">新增</a-button>
+ <a-button v-if="buttonSwitch.import" @click="handleImportXls" type="primary" icon="upload" style="margin-left:8px">导入</a-button>
+ <a-button v-if="buttonSwitch.export" @click="handleExportXls" type="primary" icon="download" style="margin-left:8px">导出</a-button>
+ <template v-if="cgButtonList && cgButtonList.length>0" v-for="(item,index) in cgButtonList">
+ <a-button
+ v-if=" item.optType=='js' "
+ :key=" 'cgbtn'+index "
+ @click="cgButtonJsHandler(item.buttonCode)"
+ type="primary"
+ :icon="item.buttonIcon"
+ style="margin-left:8px">
+ {{ item.buttonName }}
+ v-else-if=" item.optType=='action' "
+ @click="cgButtonActionHandler(item.buttonCode)"
+ <!-- 高级查询 -->
+ <j-super-query
+ ref="superQuery"
+ :fieldList="superQuery.fieldList"
+ :saveCode="$route.fullPath"
+ :loading="table.loading"
+ style="margin-left: 8px;"
+ @handleSuperQuery="handleSuperQuery"/>
+ v-if="buttonSwitch.batch_delete"
+ @click="handleDelBatch"
+ style="margin-left:8px"
+ v-show="table.selectedRowKeys.length > 0"
+ ghost
+ icon="delete">批量删除</a-button>
+ 已选择 <a style="font-weight: 600">{{ table.selectedRowKeys.length }}</a>项
+ ref="cgformAutoList"
+ :columns="table.columns"
+ :dataSource="table.dataSource"
+ :pagination="table.pagination"
+ :rowSelection="rowSelectionConfig"
+ @change="handleTableChange"
+ :scroll="table.scroll"
+ style="min-height: 300px">
+ <template slot="dateSlot" slot-scope="text">
+ <span>{{ getFormatDate(text) }}</span>
+ <template slot="htmlSlot" slot-scope="text">
+ <div v-html="text"></div>
+ <template slot="imgSlot" slot-scope="text">
+ <span v-if="!text" style="font-size: 12px;font-style: italic;">无图片</span>
+ <img v-else :src="getImgView(text)" height="25px" alt="图片不存在" style="max-width:80px;font-size: 12px;font-style: italic;"/>
+ <template slot="fileSlot" slot-scope="text">
+ <span v-if="!text" style="font-size: 12px;font-style: italic;">无文件</span>
+ v-else
+ :ghost="true"
+ icon="download"
+ @click="downloadRowFile(text)">
+ 下载
+ <template v-if="hasBpmStatus">
+ <template v-if="record.bpm_status == '1'||record.bpm_status == ''|| record.bpm_status == null">
+ <template v-if="buttonSwitch.update">
+ <a class="ant-dropdown-link">
+ 更多 <a-icon type="down" />
+ <a-menu-item >
+ <a href="javascript:;" @click="handleDetail(record)">详情</a>
+ <a href="javascript:;" @click="startProcess(record)">提交流程</a>
+ <a-menu-item v-if="buttonSwitch.delete">
+ <a-popconfirm title="确定删除吗?" @confirm="() => handleDeleteOne(record)">
+ <a-menu-item @click="handlePreviewPic(record)">审批进度</a-menu-item>
+ <template v-if="cgButtonLinkList && cgButtonLinkList.length>0" v-for="(btnItem,btnIndex) in cgButtonLinkList">
+ <a-menu-item :key=" 'cgbtnLink'+btnIndex ">
+ <a href="javascript:void(0);" @click="cgButtonLinkHandler(record,btnItem.buttonCode,btnItem.optType)">
+ <a-icon v-if="btnItem.buttonIcon" :type="btnItem.buttonIcon" />
+ {{ btnItem.buttonName }}
+ <onl-cgform-auto-modal @success="handleFormSuccess" ref="modal" :code="code" @schema="handleGetSchema" />
+ <j-import-modal ref="importModal" :url="getImportUrl()" @ok="importOk"></j-import-modal>
+ import { postAction,getAction,deleteAction,downFile } from '@/api/manage'
+ import { filterMultiDictText } from '@/components/dict/JDictSelectUtil'
+ import JImportModal from '@/components/jeecg/JImportModal'
+ import JSuperQuery from '@comp/jeecg/JSuperQuery'
+ name: 'OnlCgFormAutoList',
+ JSuperQuery,
+ JImportModal,
+ code: '',
+ description: '在线报表功能测试页面',
+ currentTableName:"",
+ getQueryInfo:'/online/cgform/api/getQueryInfo/',
+ getColumns: '/online/cgform/api/getColumns/',
+ getData: '/online/cgform/api/getData/',
+ optPre:"/online/cgform/api/form/",
+ exportXls:'/online/cgform/api/exportXls/',
+ buttonAction:'/online/cgform/api/doButton',
+ startProcess: "/process/extActProcess/startMutilProcess",
+ flowCodePre:"onl_",
+ isorter:{
+ column: 'createTime',
+ order: 'desc',
+ //dictOptions:{fieldName:[]}
+ dictOptions:{
+ cgButtonLinkList:[],
+ cgButtonList:[],
+ queryInfo:[],
+ // 查询参数,多个页面的查询参数用 code 作为键来区分
+ queryParamsMap: {},
+ toggleSearchStatus:false,
+ table: {
+ scroll:{x:false},
+ //数据集
+ // 选择器
+ selectionRows: [],
+ // 分页参数
+ pagination: {
+ metaPagination:{
+ actionColumn:{
+ fixed:"right",
+ width:150
+ formTemplate:"99",
+ EnhanceJS:'',
+ hideColumns:[],
+ buttonSwitch:{
+ add:true,
+ update:true,
+ delete:true,
+ batch_delete:true,
+ import:true,
+ export:true
+ hasBpmStatus:false,
+ checkboxFlag:false,
+ // 高级查询
+ superQuery: {
+ // 字段列表
+ fieldList: [],
+ // 查询参数
+ params: '',
+ // 查询条件拼接方式 'and' or 'or'
+ matchType: 'and'
+ this.initAutoList();
+ this.cgButtonJsHandler('mounted')
+ '$route.path'(newVal,oldVal) {
+ console.log('$route.path: ',oldVal)
+ // 刷新参数放到这里去触发,就可以刷新相同界面了
+ this.initAutoList()
+ computed:{
+ rowSelectionConfig:function() {
+ if(!this.checkboxFlag){
+ return null
+ fixed:true,
+ selectedRowKeys:this.table.selectedRowKeys,
+ onChange: this.handleChangeInTableSelect
+ queryParam: {
+ get() {
+ return this.queryParamsMap[this.code]
+ set(newVal) {
+ this.$set(this.queryParamsMap, this.code, newVal)
+ hasBpmStatusFilter(){
+ var columnObjs = this.table.columns;
+ let columns = [];
+ for (var item of columnObjs) {
+ columns.push(item.dataIndex);
+ if(columns.includes('bpm_status')||columns.includes('BPM_STATUS')){
+ this.hasBpmStatus = true;
+ this.hasBpmStatus = false;
+ startProcess: function(record){
+ var that = this;
+ title:"提示",
+ content:"确认提交流程吗?",
+ onOk: function(){
+ var param = {
+ flowCode:that.flowCodePre+that.currentTableName,
+ id:record.id,
+ formUrl:"modules/bpm/task/form/OnlineFormDetail",
+ formUrlMobile:"modules/bpm/task/form/OnlineFormDetail"
+ postAction(that.url.startProcess,param).then((res)=>{
+ that.loadData();
+ that.onClearSelected();
+ initQueryInfo(){
+ getAction(`${this.url.getQueryInfo}${this.code}`).then((res)=>{
+ console.log("--onlineList-获取查询条件配置",res);
+ this.queryInfo = res.result
+ initAutoList(){
+ // 清空高级查询条件
+ this.superQuery.params = ''
+ if (this.$refs.superQuery) {
+ this.$refs.superQuery.handleReset()
+ this.table.loading = true
+ this.code = this.$route.params.code
+ if (!this.queryParam) {
+ this.queryParam = {}
+ getAction(`${this.url.getColumns}${this.code}`).then((res)=>{
+ console.log("--onlineList-加载动态列>>",res);
+ if(res.result.checkboxFlag == 'Y'){
+ this.checkboxFlag = true
+ this.checkboxFlag = false
+ if(res.result.paginationFlag=='Y'){
+ this.table.pagination = {...this.metaPagination}
+ this.table.pagination = false
+ this.dictOptions = res.result.dictOptions
+ this.formTemplate = res.result.formTemplate
+ this.description = res.result.description
+ this.currentTableName = res.result.currentTableName
+ this.initCgButtonList(res.result.cgButtonList)
+ this.initCgEnhanceJs(res.result.enhanceJs)
+ this.initButtonSwitch(res.result.hideColumns)
+ let currColumns = res.result.columns
+ for(let a=0;a<currColumns.length;a++){
+ if(currColumns[a].customRender){
+ let dictCode = currColumns[a].customRender;
+ let replaceFlag = '_replace_text_';
+ if(dictCode.startsWith(replaceFlag)){
+ let textFieldName = dictCode.replace(replaceFlag,'')
+ currColumns[a].customRender=(text,record)=>{
+ return record[textFieldName]
+ currColumns[a].customRender=(text)=>{
+ return filterMultiDictText(this.dictOptions[dictCode], text);
+ if(res.result.scrollFlag==1){
+ this.table.scroll = { x :'115%' }
+ this.table.scroll = { x :false }
+ currColumns.push(this.actionColumn);
+ this.table.columns = [...currColumns]
+ this.hasBpmStatusFilter();
+ this.loadData();
+ this.initQueryInfo();
+ loadData(arg){
+ if(this.table.pagination){
+ if(arg==1){
+ this.table.pagination.current=1
+ let params = this.getQueryParams();//查询条件
+ console.log("--onlineList-查询条件-->",params)
+ getAction(`${this.url.getData}${this.code}`,params).then((res)=>{
+ console.log("--onlineList-列表数据",res)
+ let result = res.result;
+ if(Number(result.total)>0){
+ this.table.pagination.total = Number(result.total)
+ this.table.dataSource = result.records
+ this.table.pagination.total=0;
+ this.table.dataSource=[]
+ //this.$message.warning("查无数据")
+ this.table.loading = false
+ this.loadDataNoPage()
+ loadDataNoPage(){
+ let param = this.getQueryParams()//查询条件
+ param['pageSize'] = -521;
+ getAction(`${this.url.getData}${this.code}`,filterObj(param)).then((res)=>{
+ let param = Object.assign({}, this.queryParam,this.isorter);
+ param.pageNo = this.table.pagination.current;
+ param.pageSize = this.table.pagination.pageSize;
+ param.superQueryMatchType = this.superQuery.matchType
+ param.superQueryParams = encodeURIComponent(this.superQuery.params)
+ handleChangeInTableSelect(selectedRowKeys, selectionRows) {
+ this.table.selectedRowKeys = selectedRowKeys
+ this.table.selectionRows = selectionRows
+ handleTableChange(pagination, filters, sorter){
+ //TODO 筛选
+ if (Object.keys(sorter).length>0){
+ this.isorter.column = sorter.field;
+ this.isorter.order = "ascend"==sorter.order?"asc":"desc"
+ this.table.pagination = pagination;
+ handleAdd(){
+ this.cgButtonJsHandler('beforeAdd')
+ this.$refs.modal.add(this.formTemplate);
+ handleImportXls(){
+ this.$refs.importModal.show()
+ importOk(){
+ handleExportXls2(){
+ let param = this.queryParam;
+ if(this.table.selectedRowKeys && this.table.selectedRowKeys.length>0){
+ param['selections'] = this.table.selectedRowKeys.join(",")
+ let paramsStr = encodeURI(JSON.stringify(param));
+ console.log('paramsStr: ' + paramsStr)
+ let url = window._CONFIG['domianURL']+this.url.exportXls+this.code+"?paramsStr="+paramsStr
+ window.location.href = url;
+ handleExportXls(){
+ console.log("导出参数",param)
+ let paramsStr = JSON.stringify(filterObj(param));
+ downFile(this.url.exportXls+this.code,{paramsStr:paramsStr}).then((data)=>{
+ if (!data) {
+ this.$message.warning("文件下载失败")
+ if (typeof window.navigator.msSaveBlob !== 'undefined') {
+ window.navigator.msSaveBlob(new Blob([data]), this.description+'.xls')
+ let url = window.URL.createObjectURL(new Blob([data]))
+ let link = document.createElement('a')
+ link.style.display = 'none'
+ link.href = url
+ link.setAttribute('download', this.description+'.xls')
+ document.body.appendChild(link)
+ link.click()
+ document.body.removeChild(link); //下载完成移除元素
+ window.URL.revokeObjectURL(url); //释放掉blob对象
+ handleEdit(record){
+ this.cgButtonLinkHandler(record,"beforeEdit","js")
+ this.$refs.modal.edit(this.formTemplate,record.id);
+ handleDetail(record){
+ this.$refs.modal.detail(this.formTemplate,record.id);
+ handleDeleteOne(record){
+ this.cgButtonLinkHandler(record,"beforeDelete","js")
+ this.handleDelete(record.id)
+ handleDelete(id){
+ deleteAction(this.url.optPre+this.code+"/"+id).then((res)=>{
+ handleFormSuccess(){
+ // 查询完 schema 后,生成高级查询的字段列表
+ handleGetSchema(schema) {
+ if (schema && schema.properties) {
+ let setField = (array, field) => {
+ let type = field.type || 'string'
+ type = (type === 'inputNumber' ? 'number' : type)
+ array.push({
+ type: type,
+ value: field.key,
+ text: field.title,
+ // 额外字典参数
+ dictCode: field.dictCode,
+ dictTable: field.dictTable,
+ dictText: field.dictText,
+ options: field.enum || field.options
+ let fieldList = []
+ for (let key in schema.properties) {
+ if (!schema.properties.hasOwnProperty(key)) {
+ continue
+ let field = schema.properties[key]
+ // tab = 子表
+ if (field.view === 'tab') {
+ let subTable = {
+ type: 'sub-table',
+ text: field.describe,
+ children: []
+ for (let column of field.columns) {
+ setField(subTable.children, column)
+ fieldList.push(subTable)
+ field.key = key
+ setField(fieldList, field)
+ this.superQuery.fieldList = fieldList
+ onClearSelected(){
+ this.table.selectedRowKeys = []
+ this.table.selectionRows = []
+ getImgView(text){
+ if(text && text.indexOf(",")>0){
+ text = text.substring(0,text.indexOf(","))
+ return window._CONFIG['imgDomainURL']+"/"+text
+ downloadRowFile(text){
+ if(!text){
+ this.$message.warning("未知的文件")
+ return;
+ if(text.indexOf(",")>0){
+ window.open(window._CONFIG['downloadUrl']+"/"+text);//TODO 下载的方法
+ handleDelBatch(){
+ if(this.table.selectedRowKeys.length<=0){
+ this.$message.warning('请选择一条记录!');
+ return false;
+ let ids = "";
+ let that = this;
+ that.table.selectedRowKeys.forEach(function(val) {
+ ids+=val+",";
+ that.$confirm({
+ title:"确认删除",
+ content:"是否删除选中数据?",
+ that.handleDelete(ids)
+ searchByquery(){
+ this.loadData(1);
+ searchReset(){
+ handleToggleSearch(){
+ this.toggleSearchStatus = !this.toggleSearchStatus;
+ getFormatDate(text){
+ let a = text;
+ if(a.length>10){
+ a = a.substring(0,10);
+ return a;
+ getImportUrl(){
+ return '/online/cgform/api/importXls/'+this.code
+ initCgEnhanceJs(enhanceJs){
+ //console.log("--onlineList-js增强",enhanceJs)
+ if(enhanceJs){
+ let Obj = eval ("(" + enhanceJs + ")");
+ this.EnhanceJS = new Obj(getAction,postAction,deleteAction);
+ this.cgButtonJsHandler('created')
+ this.EnhanceJS = ''
+ initCgButtonList(btnList){
+ let linkArr = []
+ let buttonArr = []
+ if(btnList && btnList.length>0){
+ for(let i=0;i<btnList.length;i++){
+ let temp = btnList[i]
+ if(temp.buttonStyle=='button'){
+ buttonArr.push(temp)
+ }else if(temp.buttonStyle=='link'){
+ linkArr.push(temp)
+ this.cgButtonLinkList = [...linkArr]
+ this.cgButtonList=[...buttonArr]
+ cgButtonJsHandler(buttonCode){
+ if(this.EnhanceJS[buttonCode]){
+ this.EnhanceJS[buttonCode](this)
+ cgButtonActionHandler(buttonCode){
+ //处理自定义button的 需要配置该button自定义sql
+ if(!this.table.selectedRowKeys || this.table.selectedRowKeys.length==0){
+ this.$message.warning("请先选中一条记录")
+ if(this.table.selectedRowKeys.length>1){
+ this.$message.warning("请只选中一条记录")
+ formId:this.code,
+ buttonCode:buttonCode,
+ dataId:this.table.selectedRowKeys[0]
+ console.log("自定义按钮请求后台参数:",params)
+ postAction(this.url.buttonAction,params).then(res=>{
+ this.$message.success("处理完成!")
+ this.$message.warning("处理失败!")
+ cgButtonLinkHandler(record,buttonCode,optType){
+ if(optType=="js"){
+ this.EnhanceJS[buttonCode](this,record)
+ }else if(optType=="action"){
+ dataId:record.id
+ console.log("自定义按钮link请求后台参数:",params)
+ initButtonSwitch(hideColumns){
+ if(hideColumns && hideColumns.length>0){
+ Object.keys(this.buttonSwitch).forEach(key=>{
+ if(hideColumns.indexOf(key)>=0){
+ this.buttonSwitch[key]=false
+ handleSuperQuery(params, matchType) {
+ if (!params || params.length === 0) {
+ this.superQuery.params = JSON.stringify(params)
+ this.superQuery.matchType = matchType
+ .ant-card-body .table-operator{
+ .ant-table-tbody .ant-table-row td{
+ padding-top:15px;
+ padding-bottom:15px;
+ .anty-row-operator button{margin: 0 5px}
+ .ant-btn-danger{background-color: #ffffff}
+ .anty-img-wrap{height:25px;position: relative;}
+ .anty-img-wrap > img{max-height:100%;}
+ .ant-modal-cust-warp{height: 100%}
+ .ant-modal-cust-warp .ant-modal-body{height:calc(100% - 110px) !important;overflow-y: auto}
+ .ant-modal-cust-warp .ant-modal-content{height:90% !important;overflow-y: hidden}
@@ -0,0 +1,713 @@
+ v-show="selectedRowKeys.length > 0"
+ 已选择 <a style="font-weight: 600">{{ selectedRowKeys.length }}</a>项
+ ref="cgformTreeList"
+ :pagination="pagination"
+ v-bind="tableProps"
+ @expand="handleExpand"
+ style="min-height: 300px"
+ :expandedRowKeys="expandedRowKeys">
+ <span>{{ getDateNoTime(text) }}</span>
+ <template v-if="showOptButton('update',record)">
+ <a @click="handleDetail(record)">详情</a>
+ <a-menu-item v-if="showSubmitFlowButton(record)">
+ <a @click="startProcess(record)">提交流程</a>
+ <template v-if="showViewFlowButton(record)">
+ <a-menu-item v-if="showOptButton('delete',record)">
+ <!-- 自定义按钮 -->
+ <onl-cgform-auto-modal @success="handleFormSuccess" ref="modal" :code="code"></onl-cgform-auto-modal>
+ import { getAction,postAction,deleteAction,downFile } from '@/api/manage'
+ name: 'OnlCgformTreeList',
+ JImportModal
+ code: '87b55a515d3441b6b98e48e5b35474a6',
+ pidField:"",
+ hasChildrenField:"",
+ textField:'',
+ getTreeData: '/online/cgform/api/getTreeData/',
+ startProcess: "/process/extActProcess/startMutilProcess"
+ column: 'create_time',
+ queryParam:{
+ /*自定义按钮-link*/
+ /*自定义按钮-button*/
+ /*JS增强*/
+ /*操作按钮权限*/
+ expandedRowKeys:[],
+ this.initAutoListConfig().then(()=>{
+ }).catch(msg=>{
+ console.log(msg)
+ //this.cgButtonJsHandler('mounted')
+ tableProps() {
+ let _this = this
+ // 列表项是否可选择
+ // https://vue.ant.design/components/table-cn/#rowSelection
+ rowSelection: {
+ selectedRowKeys: _this.selectedRowKeys,
+ onChange: (selectedRowKeys) => _this.selectedRowKeys = selectedRowKeys
+ resetData(){
+ this.description=''
+ this.currentTableName=''
+ this.pidField=''
+ this.hasChildrenField=''
+ this.textField=''
+ this.columns = []
+ this.selectedRowKeys=[]
+ this.selectionRows=[]
+ initAutoListConfig() {
+ return new Promise((resolve, reject) => {
+ if (!this.$route.params.code) {
+ reject("列表加载需要参数CODE为空!")
+ this.resetData()
+ getAction(`${this.url.getColumns}${this.code}`)
+ .then(res => {
+ console.log("--onlineList-加载动态列>>", res);
+ this.configInfohandler(res)
+ reject("onlineList-加载表配置信息失败")
+ .catch(err => {
+ reject(err)
+ configInfohandler(res){
+ this.pidField = res.result.pidField
+ this.hasChildrenField = res.result.hasChildrenField
+ this.textField = res.result.textField
+ //自定义按钮
+ //JS增强
+ //操作按钮权限
+ let textFieldIndex = -1
+ let hasBpmStatus = false
+ currColumns[a].align = 'left'
+ //找到显示列
+ if(this.textField==currColumns[a].dataIndex){
+ textFieldIndex = a
+ //数据字典翻译
+ //判断是否有bpm_status
+ if(currColumns[a].dataIndex.toLowerCase()=='bpm_status'){
+ hasBpmStatus = true;
+ this.hasBpmStatus = hasBpmStatus;
+ if(textFieldIndex!=-1){
+ let textFieldColumn = currColumns.splice(textFieldIndex,1)
+ currColumns.unshift(textFieldColumn[0])
+ this.columns = [...currColumns]
+ //加载根节点
+ this.pagination.current=1
+ this.expandedRowKeys=[]
+ params[this.pidField]='0'
+ getAction(`${this.url.getTreeData}${this.code}`,params).then((res)=>{
+ this.pagination.total = Number(result.total)
+ let dataSource = res.result.records.map(item => {
+ // 判断是否标记了带有子级
+ if (item[this.hasChildrenField] === true || item[this.hasChildrenField]=='1') {
+ let loadChild = { id: `${item.id}_loadChild`, name: 'loading...', isLoading: true }
+ item.children = [loadChild]
+ this.dataSource = dataSource
+ this.pagination.total=0;
+ this.dataSource=[]
+ //加载叶子节点
+ handleExpand(expanded, record) {
+ // 判断是否是展开状态
+ if (expanded) {
+ this.expandedRowKeys.push(record.id)
+ if (record.children.length>0 && record.children[0].isLoading === true) {
+ params[this.pidField] = record.id
+ if(Number(res.result.total)>0){
+ record.children = dataSource
+ record.children=''
+ record.hasChildrenField='0'
+ let keyIndex = this.expandedRowKeys.indexOf(record.id)
+ if(keyIndex>=0){
+ this.expandedRowKeys.splice(keyIndex, 1);
+ param.pageNo = this.pagination.current;
+ param.pageSize = this.pagination.pageSize;
+ this.selectionRows = []
+ this.pagination = pagination;
+ /*-------数据格式化-begin----------*/
+ getDateNoTime(text){
+ window.open(window._CONFIG['downloadUrl']+"/"+text);
+ /*-------数据格式化-end----------*/
+ /*-------功能按钮触发事件-begin----------*/
+ if(this.selectedRowKeys && this.selectedRowKeys.length>0){
+ param['selections'] = this.selectedRowKeys.join(",")
+ if(this.selectedRowKeys.length<=0){
+ that.selectedRowKeys.forEach(function(val) {
+ /*-------JS增强-begin----------*/
+ if(!this.selectedRowKeys || this.selectedRowKeys.length==0){
+ if(this.selectedRowKeys.length>1){
+ dataId:this.selectedRowKeys[0]
+ /*-------JS增强-end----------*/
+ showOptButton(opt,record){
+ //只有当按钮属性为false,或是按钮属性为true但是流程已提交时才隐藏
+ if(!this.buttonSwitch[opt]){
+ if(this.hasBpmStatus){
+ if(record.bpm_status !=null && record.bpm_status !='' && record.bpm_status != '1'){
+ showSubmitFlowButton(record){
+ if(record.bpm_status ==null || record.bpm_status =='' || record.bpm_status == '1'){
+ showViewFlowButton(record){
@@ -0,0 +1,268 @@
+ * 同步列表,可以同步新增、修改、删除
+export function syncAllTable(vm, table1) {
+ vm.$refs.editableTable.resetScrollTop()
+ let deleteIds = table1.$refs.editableTable.getDeleteIds()
+ let table1Value
+ table1.$refs.editableTable.getValuesPromise(false).then((values) => {
+ table1Value = values
+ return vm.$refs.editableTable.getValuesPromise(false)
+ }).then((values) => {
+ table1Value.forEach(value => {
+ let flag = false
+ values.forEach((thisValue) => {
+ if (value.id === thisValue.id) {
+ // 判断是否修改了值
+ let dbFieldName = thisValue['dbFieldName']
+ let dbFieldTxt = thisValue['dbFieldTxt']
+ // return
+ if (value.dbFieldName !== dbFieldName
+ || value.dbFieldTxt !== dbFieldTxt) {
+ // 修改了
+ vm.$refs.editableTable.setValues([{
+ rowKey: thisValue.id,
+ values: {
+ dbFieldName: value.dbFieldName,
+ dbFieldTxt: value.dbFieldTxt
+ flag = true
+ // id不匹配则有可能是新增也有可能是删除了的
+ // 遍历传进来的 deleteIds 进行对比
+ deleteIds.forEach(delId => {
+ // 对比成功,则删除该条数据
+ if (delId === thisValue.id) {
+ vm.$refs.editableTable.removeRows(vm.$refs.editableTable.caseId + delId)
+ // 判断是否操作了该条数据,若没有操作则代表要执行新增操作
+ if (!flag) {
+ let record = Object.assign({}, value)
+ vm.columns.forEach(column => {
+ if (
+ column.dataIndex !== 'dbFieldName' &&
+ column.dataIndex !== 'dbFieldTxt'
+ ) {
+ record[column.dataIndex] = column.defaultValue
+ vm.$refs.editableTable.push(record)
+ * 将数据分类并Set进dataSource
+ **/
+export function setDataSource(vm, queryData) {
+ let dataSource = []
+ // 遍历查询出来的数据
+ queryData.forEach(value => {
+ let data = { id: value['id'] }
+ let key = column.key
+ if (key) {
+ data[key] = value[key]
+ // 由于多选下拉框返回的是一个数组,所以需要改成 [1,2,3] 数组的形式,否则组件不识别
+ // if (key === 'indexField') {
+ // data[key] = value[key].split(',')
+ dataSource.push(data)
+ vm.dataSource = dataSource
+/** 获取主表的初始化数据 */
+export function getMasterTableInitialData() {
+ return [
+ dbFieldName: 'id',
+ dbFieldTxt: '主键',
+ dbLength: 36,
+ dbPointLength: 0,
+ dbDefaultVal: '',
+ dbType: 'string',
+ dbIsKey: '1',
+ dbIsNull: '0',
+ // table2
+ isShowForm: '0',
+ isShowList: '0',
+ fieldShowType: 'text',
+ fieldLength: '120',
+ queryMode: 'single',
+ orderNum: 1
+ dbFieldName: 'create_by',
+ dbFieldTxt: '创建人',
+ dbLength: 50,
+ dbIsKey: '0',
+ dbIsNull: '1',
+ orderNum: 2
+ dbFieldName: 'create_time',
+ dbFieldTxt: '创建日期',
+ dbLength: 20,
+ dbType: 'Date',
+ fieldShowType: 'datetime',
+ orderNum: 3
+ dbFieldName: 'update_by',
+ dbFieldTxt: '更新人',
+ orderNum: 4
+ dbFieldName: 'update_time',
+ dbFieldTxt: '更新日期',
+ orderNum: 5
+ dbFieldName: 'sys_org_code',
+ dbFieldTxt: '所属部门',
+ dbLength: 64,
+ orderNum: 6
+ // {
+ // dbFieldName: 'sys_org_code',
+ // dbFieldTxt: '所属部门',
+ // dbLength: 50,
+ // dbPointLength: 0,
+ // dbDefaultVal: '',
+ // dbType: 'string',
+ // dbIsKey: false,
+ // dbIsNull: true
+ // }, {
+ // dbFieldName: 'sys_company_code',
+ // dbFieldTxt: '所属公司',
+ // dbFieldName: 'bpm_status',
+ // dbFieldTxt: '流程状态',
+ // dbLength: 32,
+/** 获取树的初始化数据 */
+export function getTreeNeedFields() {
+ return [{
+ dbFieldName: 'pid',
+ dbFieldTxt: '父级节点',
+ dbLength: 32,
+ isShowForm: '1',
+ orderNum: 7
+ dbFieldName: 'has_child',
+ dbFieldTxt: '是否有子节点',
+ dbLength: 3,
+ fieldShowType: 'list',
+ orderNum: 8,
+ // table3
+ dictField:"yn"
@@ -0,0 +1,256 @@
+ <a-form-item label="报表编码">
+ <a-input placeholder="请输入报表编码" v-model="queryParam.code"></a-input>
+ <a-form-item label="报表名字">
+ <a-input placeholder="请输入报表名字" v-model="queryParam.name"></a-input>
+ <a-button @click="handleAdd" type="primary" icon="plus">录入</a-button>
+ <a style="font-weight: 600">
+ {{ selectedRowKeys.length }}
+ <a class="ant-dropdown-link">更多 <a-icon type="down"/></a>
+ <a-menu-item @click="popReportURL(record.id)">
+ 配置地址
+ <a @click="goPageOnline(record.id)">功能测试</a>
+ <onlCgreportHead-modal ref="modalForm" @ok="modalFormOk"></onlCgreportHead-modal>
+ title="报表访问链接"
+ @cancel="handleCancel">
+ <a-button @click="handleCancel">关闭</a-button>
+ <a-button type="primary" class="copy-this-text" :data-clipboard-text="reportUrlText" @click="onCopyUrl">复制</a-button>
+ <p>{{ reportUrlText }}</p>
+ import {JeecgListMixin} from '@/mixins/JeecgListMixin'
+ name: 'OnlCgreportHeadList',
+ Clipboard
+ description: '在线报表配置管理页面',
+ visible:false,
+ reportUrlText:'',
+ title: '报表名称',
+ title: '编码',
+ dataIndex: 'code'
+ title: '查询SQL',
+ dataIndex: 'cgrSql'
+ title: '数据源',
+ dataIndex: 'dbSource'
+ title: '描述',
+ dataIndex: 'content'
+ list: '/online/cgreport/head/list',
+ delete: '/online/cgreport/head/delete',
+ deleteBatch: '/online/cgreport/head/deleteBatch',
+ getParamsInfo:'/online/cgreport/api/getParamsInfo/'
+ initReportUrlText(id){
+ getAction(this.url.getParamsInfo+id).then((res) => {
+ let textUrl = ""
+ if(res.result && res.result.length>0){
+ textUrl+=i.paramName+"=${"+i.paramName+"}&"
+ if(textUrl.length>0){
+ textUrl = textUrl.substring(0,textUrl.length-1)
+ this.reportUrlText = `/online/cgreport/${id}?${textUrl}`
+ this.reportUrlText = `/online/cgreport/${id}`
+ goPageOnline(id){
+ this.$router.push({path: '/online/cgreport/'+id})
+ popReportURL(id){
+ this.initReportUrlText(id)
+ handleCancel(){
+ this.reportUrlText = '';
+ this.handleCancel()
@@ -0,0 +1,293 @@
+ <a-col v-if="item.view.indexOf('Date')>=0" :md="12" :sm="16" :key=" 'query'+index " v-show="toggleSearchStatus">
+ <onl-cgreport-query-form-item :queryParam="queryParam" :item="item" :dictOptions="dictOptions"></onl-cgreport-query-form-item>
+ <a-col v-if="item.view.indexOf('Date')>=0" :md="12" :sm="16" :key=" 'query'+index ">
+ <a-button type="primary" @click="searchByQuery" icon="search">查询</a-button>
+ <div class="table-operator" style="margin-bottom: 10px">
+ <a-button type="primary" icon="plus" @click="exportExcel">导出</a-button>
+ :rowSelection="{fixed:true, selectedRowKeys: table.selectedRowKeys, onChange: handleChangeInTableSelect}"
+ @change="handleChangeInTable"
+ import { getAction,downFile } from '@/api/manage'
+ import {filterObj} from '@/utils/util';
+ name: 'OnlCgreportAutoList',
+ queryInfo: [],
+ selfParam:{
+ sorter: {
+ column: '',
+ dictOptions: {},
+ toggleSearchStatus: false, // 高级搜索 展开/关闭
+ reportCode: '',
+ getColumns: '/online/cgreport/api/getColumns/',
+ getData: '/online/cgreport/api/getData/',
+ getQueryInfo: '/online/cgreport/api/getQueryInfo/',
+ scroll: { x: false },
+ cgreportHeadName:""
+ this.initParamsInfo()
+ return this.queryParamsMap[this.reportCode]
+ this.$set(this.queryParamsMap, this.reportCode, newVal)
+ initParamsInfo(){
+ //获取报表ID
+ this.reportCode = this.$route.params.code;
+ this.selfParam={}
+ getAction(`${this.url.getParamsInfo}${this.$route.params.code}`).then((res) => {
+ this.selfParam['self_'+i.paramName]=(!this.$route.query[i.paramName])?"":this.$route.query[i.paramName]
+ initQueryInfo() {
+ getAction(`${this.url.getQueryInfo}${this.$route.params.code}`).then((res) => {
+ console.log("获取查询条件", res);
+ if (arg == 1) {
+ this.table.pagination.current = 1
+ console.log(' 动态报表 reportCode : ' + this.reportCode);
+ Promise.all([
+ getAction(`${this.url.getColumns}${this.reportCode}`),
+ getAction(`${this.url.getData}${this.reportCode}`, params)
+ ]).then(results => {
+ let [{result: {columns,cgreportHeadName,dictOptions}}, {result: data}] = results
+ let columnWidth = 230
+ this.dictOptions = dictOptions
+ for(let a=0;a<columns.length;a++){
+ if(columns[a].customRender){
+ let field_name = columns[a].customRender;
+ columns[a].customRender=(text)=>{
+ return filterMultiDictText(this.dictOptions[field_name], text+"");
+ columns.width = columnWidth
+ this.table.scroll.x = columns.length * columnWidth
+ this.table.columns = [...columns]
+ this.cgreportHeadName = cgreportHeadName
+ if (data) {
+ this.table.pagination.total = Number(data.total)
+ this.table.dataSource = data.records
+ this.table.pagination.total = 0
+ this.table.dataSource = []
+ }).catch((e) => {
+ console.error(e)
+ this.$message.error('查询失败')
+ }).then(() => {
+ let param = Object.assign({}, this.queryParam, this.sorter,this.selfParam);
+ searchByQuery() {
+ searchReset() {
+ handleToggleSearch() {
+ exportExcel() {
+ let fileName = this.cgreportHeadName
+ downFile(`/online/cgreport/api/exportXls/${this.reportCode}`,this.queryParam).then((data)=>{
+ window.navigator.msSaveBlob(new Blob([data]), fileName+'.xls')
+ link.setAttribute('download', fileName+'.xls')
+ handleChangeInTable(pagination, filters, sorter) {
+ //分页、排序、筛选变化时触发
+ if (Object.keys(sorter).length > 0) {
+ this.sorter.column = sorter.field
+ this.sorter.order = 'ascend' == sorter.order ? 'asc' : 'desc'
+ this.table.pagination = pagination
+ .div {
+ align-items: center;
+ height: 500px
+ <a-form layout="inline" @keyup.enter.native="searchQuery">
+ <a-form-item label="文件名称">
+ <a-input placeholder="请输入文件名称" v-model="queryParam.fileName"></a-input>
+ <a-form-item label="文件地址">
+ <a-input placeholder="请输入文件地址" v-model="queryParam.url"></a-input>
+ <!-- <a-button type="primary" icon="download" @click="handleExportXls('文件列表')">导出</a-button>-->
+ <a-upload
+ name="file"
+ :multiple="false"
+ :action="uploadAction"
+ :headers="tokenHeader"
+ :showUploadList="false"
+ :beforeUpload="beforeUpload"
+ @change="handleChange">
+ <a-button>
+ <a-icon type="upload"/>
+ 文件上传
+ <i class="anticon anticon-info-circle ant-alert-icon"></i> 已选择 <a
+ style="font-weight: 600">{{
+ selectedRowKeys.length }}</a>项
+ <a @click="ossDelete(record.id)">删除</a>
+ name: "OSSFileList",
+ description: '文件列表',
+ align: "center",
+ customRender: function (t, r, index) {
+ return parseInt(index) + 1;
+ title: '文件名称',
+ dataIndex: 'fileName'
+ title: '文件地址',
+ dataIndex: 'url'
+ scopedSlots: {customRender: 'action'},
+ upload: "/oss/file/upload",
+ list: "/oss/file/list",
+ delete: "/oss/file/delete"
+ uploadAction() {
+ return window._CONFIG['domianURL'] + this.url.upload;
+ beforeUpload(file) {
+ var fileType = file.type;
+ if (fileType === 'image') {
+ if (fileType.indexOf('image') < 0) {
+ this.$message.warning('请上传图片');
+ } else if (fileType === 'file') {
+ if (fileType.indexOf('image') >= 0) {
+ this.$message.warning('请上传文件');
+ handleChange(info) {
+ if (info.file.status === 'done') {
+ if (info.file.response.success) {
+ this.$message.success(`${info.file.name} 上传成功!`);
+ this.$message.error(`${info.file.name} 上传失败.`);
+ } else if (info.file.status === 'error') {
+ ossDelete(id) {
+ title: "确认删除",
+ content: "是否删除选中文件?",
+ onOk: function () {
+ that.handleDelete(id)
@@ -0,0 +1,31 @@
+ <a-row type="flex" :gutter="16">
+ <a-col :md="5" :sm="24">
+ <address-list-left v-model="currentOrgCode"/>
+ <a-col :md="24-5" :sm="24">
+ <address-list-right v-model="currentOrgCode"/>
+ import AddressListLeft from './modules/AddressListLeft'
+ import AddressListRight from './modules/AddressListRight'
+ name: 'AddressList',
+ components: { AddressListLeft, AddressListRight },
+ description: '通讯录页面',
+ currentOrgCode: ''
+ methods: {}
+ @import '~@assets/less/common.less';
+ :style="modalStyle"
+ :maskClosable="false"
+ <a @click="handleBack(record.id)"><a-icon type="redo"/>字典取回</a>
+ <a @click="handleDelete(record.id)"><a-icon type="scissor"/>彻底删除</a>
+ import { getAction,deleteAction,putAction } from '@/api/manage'
+ name: "DictDeleteList",
+ modalWidth: '90%',
+ modalStyle: { 'top': '20px'},
+ dataSource:[],
+ columns:[
+ width: 120,
+ title: '字典名称',
+ align: "left",
+ dataIndex: 'dictName'
+ title: '字典编号',
+ dataIndex: 'dictCode'
+ dataIndex: 'description'
+ scopedSlots: {customRender: 'action'}
+ loadData(){
+ getAction("/sys/dict/deleteList").then(res=>{
+ this.dataSource = res.result
+ handleBack(id){
+ putAction("/sys/dict/back/"+id).then(res=>{
+ deleteAction("/sys/dict/deletePhysic/"+id).then(res=>{
@@ -0,0 +1,198 @@
+ @click="batchDel"
+ v-if="selectedRowKeys.length > 0"
+ icon="delete">批量删除
+ <i class="anticon anticon-info-circle ant-alert-icon"></i>已选择 <a style="font-weight: 600">{{
+ selectedRowKeys.length }}</a>项
+ @expand="expandSubmenu"
+ :rowSelection="{selectedRowKeys: selectedRowKeys, onChange: onSelectChange}">
+ 更多 <a-icon type="down"/>
+ <a href="javascript:;" @click="handleAddSub(record)">添加子菜单</a>
+ <a href="javascript:;" @click="handleDataRule(record)">数据规则</a>
+ <!-- 字符串超长截取省略号显示 -->
+ <span slot="url" slot-scope="text">
+ <j-ellipsis :value="text" :length="25"/>
+ <!-- 字符串超长截取省略号显示-->
+ <span slot="component" slot-scope="text">
+ <j-ellipsis :value="text"/>
+ <permission-modal ref="modalForm" @ok="modalFormOk"></permission-modal>
+ <permission-data-rule-list ref="PermissionDataRuleList" @ok="modalFormOk"></permission-data-rule-list>
+ import PermissionModal from './modules/PermissionModal'
+ import { getSystemMenuList,getSystemSubmenu } from '@/api/api'
+ import PermissionDataRuleList from './PermissionDataRuleList'
+ const columns = [
+ title: '菜单名称',
+ key: 'name'
+ title: '菜单类型',
+ dataIndex: 'menuType',
+ key: 'menuType',
+ customRender: function(text) {
+ if (text == 0) {
+ return '菜单'
+ } else if (text == 1) {
+ } else if (text == 2) {
+ return '按钮/权限'
+ return text
+ },/*{
+ title: '权限编码',
+ dataIndex: 'perms',
+ key: 'permissionCode',
+ },*/{
+ title: 'icon',
+ dataIndex: 'icon',
+ key: 'icon'
+ title: '组件',
+ dataIndex: 'component',
+ key: 'component',
+ scopedSlots: { customRender: 'component' }
+ title: '路径',
+ dataIndex: 'url',
+ key: 'url',
+ scopedSlots: { customRender: 'url' }
+ title: '排序',
+ dataIndex: 'sortNo',
+ key: 'sortNo'
+ width: 150
+ name: 'PermissionList',
+ PermissionDataRuleList,
+ PermissionModal,
+ JEllipsis
+ description: '这是菜单管理页面',
+ columns: columns,
+ list: '/sys/permission/list',
+ delete: '/sys/permission/delete',
+ deleteBatch: '/sys/permission/deleteBatch'
+ loadData() {
+ getSystemMenuList().then((res) => {
+ console.log(res.result)
+ expandSubmenu(expanded, record){
+ if(expanded){
+ getSystemSubmenu({parentId:record.id}).then((res) => {
+ record.children = res.result
+ // 打开数据规则编辑
+ handleDataRule(record) {
+ this.$refs.PermissionDataRuleList.edit(record)
+ handleAddSub(record) {
+ this.$refs.modalForm.title = "添加子菜单";
+ this.$refs.modalForm.localMenuType = 1;
+ this.$refs.modalForm.disableSubmit = false;
+ this.$refs.modalForm.edit({status:'1',permsType:'1',route:true,'parentId':record.id});
@@ -0,0 +1,187 @@
+ <a-form-item label="规则名称">
+ <a-input placeholder="请输入规则名称" v-model="queryParam.ruleName"></a-input>
+ <a-form-item label="规则Code">
+ <a-input placeholder="请输入规则Code" v-model="queryParam.ruleCode"></a-input>
+ <a-button type="primary" icon="download" @click="handleExportXls('填值规则')">导出</a-button>
+ <a-alert type="info" showIcon style="margin-bottom: 16px;">
+ <template slot="message">
+ <span>已选择</span>
+ <a style="font-weight: 600;padding: 0 4px;">{{ selectedRowKeys.length }}</a>
+ <span>项</span>
+ <template v-if="selectedRowKeys.length>0">
+ <a @click="onClearSelected">清空</a>
+ </a-alert>
+ <a-menu-item @click="handleTest(record)">
+ 功能测试
+ <sys-fill-rule-modal ref="modalForm" @ok="modalFormOk"/>
+ import SysFillRuleModal from './modules/SysFillRuleModal'
+ name: 'SysFillRuleList',
+ components: { SysFillRuleModal },
+ description: '填值规则管理页面',
+ customRender: (t, r, index) => 1 + index
+ title: '规则名称',
+ dataIndex: 'ruleName'
+ title: '规则Code',
+ dataIndex: 'ruleCode'
+ title: '规则实现类',
+ dataIndex: 'ruleClass'
+ title: '规则参数',
+ dataIndex: 'ruleParams'
+ list: '/sys/fillRule/list',
+ test: '/sys/fillRule/testFillRule',
+ delete: '/sys/fillRule/delete',
+ deleteBatch: '/sys/fillRule/deleteBatch',
+ exportXlsUrl: '/sys/fillRule/exportXls',
+ importExcelUrl: '/sys/fillRule/importExcel',
+ importExcelUrl() {
+ return `${window._CONFIG['domianURL']}${this.url.importExcelUrl}`
+ handleTest(record) {
+ let closeLoading = this.$message.loading('生成中...', 0)
+ getAction(this.url.test, {
+ ruleCode: record.ruleCode
+ this.$info({
+ title: '填值规则功能测试',
+ content: '生成结果:' + res.result
+ this.$message.warn(res.message)
+ closeLoading()
@@ -0,0 +1,178 @@
+ <a-form-item label="职务编码">
+ <a-input placeholder="请输入职务编码" v-model="queryParam.code"></a-input>
+ <a-form-item label="职务名称">
+ <a-input placeholder="请输入职务名称" v-model="queryParam.name"></a-input>
+ <a-form-item label="职级">
+ <j-dict-select-tag v-model="queryParam.postRank" placeholder="请选择职级" dictCode="position_rank"/>
+ <a-button type="primary" icon="download" @click="handleExportXls('职务表')">导出</a-button>
+ <sysPosition-modal ref="modalForm" @ok="modalFormOk"></sysPosition-modal>
+ import SysPositionModal from './modules/SysPositionModal'
+ import JDictSelectTag from '@/components/dict/JDictSelectTag'
+ name: 'SysPositionList',
+ SysPositionModal,
+ JDictSelectTag
+ description: '职务表管理页面',
+ title: '职务编码',
+ title: '职务名称',
+ title: '职级',
+ dataIndex: 'postRank_dictText'
+ // title: '公司id',
+ // align: 'center',
+ // dataIndex: 'companyId'
+ // },
+ list: '/sys/position/list',
+ delete: '/sys/position/delete',
+ deleteBatch: '/sys/position/deleteBatch',
+ exportXlsUrl: '/sys/position/exportXls',
+ importExcelUrl: '/sys/position/importExcel',
+ importExcelUrl: function () {
+ return `${window._CONFIG['domianURL']}/${this.url.importExcelUrl}`
@@ -0,0 +1,98 @@
+ <a-card :loading="cardLoading" :bordered="false" style="height: 100%;">
+ <a-input-search @search="handleSearch" style="width:100%;margin-top: 10px" placeholder="输入组织机构名称进行查询..."/>
+ <a-tree
+ showLine
+ checkStrictly
+ :expandedKeys.sync="expandedKeys"
+ :selectedKeys="selectedKeys"
+ :dropdownStyle="{maxHeight:'200px',overflow:'auto'}"
+ :treeData="treeDataSource"
+ @select="handleTreeSelect"
+ import { queryDepartTreeList, searchByKeywords } from '@/api/api'
+ name: 'AddressListLeft',
+ cardLoading: true,
+ treeDataSource: [],
+ selectedKeys: [],
+ expandedKeys: []
+ this.queryTreeData()
+ queryTreeData(keyword) {
+ this.commonRequestThen(queryDepartTreeList({
+ departName: keyword ? keyword : undefined
+ handleSearch(value) {
+ this.commonRequestThen(searchByKeywords({ keyWord: value }))
+ handleTreeSelect(selectedKeys, event) {
+ if (selectedKeys.length > 0 && this.selectedKeys[0] !== selectedKeys[0]) {
+ this.selectedKeys = [selectedKeys[0]]
+ let orgCode = event.node.dataRef.orgCode
+ this.emitInput(orgCode)
+ emitInput(orgCode) {
+ this.$emit('input', orgCode)
+ commonRequestThen(promise) {
+ promise.then(res => {
+ this.treeDataSource = res.result
+ // 默认选中第一条数据、默认展开所有第一级
+ this.expandedKeys = []
+ res.result.forEach((item, index) => {
+ if (index === 0) {
+ this.selectedKeys = [item.id]
+ this.emitInput(item.orgCode)
+ this.expandedKeys.push(item.id)
+ this.$message.warn('组织机构查询失败:' + res.message)
+ console.error('组织机构查询失败:', res)
+ this.cardLoading = false
+ <a-card class="j-address-list-right-card-box" :loading="cardLoading" :bordered="false">
+ <a-row :gutter="10">
+ <a-col :md="6" :sm="12">
+ <a-form-item label="姓名" style="margin-left:8px">
+ <a-input placeholder="请输入姓名查询" v-model="queryParam.realname"></a-input>
+ <a-form-item label="工号" style="margin-left:8px">
+ <a-input placeholder="请输入工号查询" v-model="queryParam.workNo"></a-input>
+ <a-button type="primary" @click="searchQuery" icon="search" style="margin-left: 18px">查询</a-button>
+ rowKey="userId"
+ name: 'AddressListRight',
+ description: '用户信息',
+ positionInfo: {},
+ customRender: (t, r, i) => parseInt(i) + 1
+ title: '部门',
+ width: '20%',
+ dataIndex: 'departName'
+ width: '15%',
+ dataIndex: 'realname'
+ title: '工号',
+ dataIndex: 'workNo'
+ title: '职务',
+ dataIndex: 'post',
+ customRender: (text) => (text || '').split(',').map(t => this.positionInfo[t] ? this.positionInfo[t] : t).join(',')
+ title: '座机',
+ dataIndex: 'telephone'
+ // title: '手机号',
+ // width: '12%',
+ // dataIndex: 'phone'
+ title: '公司邮箱',
+ dataIndex: 'email'
+ list: '/sys/user/queryByOrgCodeForAddressList',
+ listByPosition: '/sys/position/list'
+ handler(orgCode) {
+ this.loadData(1, orgCode)
+ this.queryPositionInfo()
+ loadData(pageNum, orgCode) {
+ if (!orgCode) {
+ if (pageNum === 1) {
+ getAction(this.url.list, {
+ orgCode,
+ ...this.getQueryParams()
+ searchQuery() {
+ this.loadData(1, this.value)
+ handleTableChange(pagination, filters, sorter) {
+ this.isorter.column = sorter.field
+ this.isorter.order = 'ascend' === sorter.order ? 'asc' : 'desc'
+ this.ipagination = pagination
+ this.loadData(null, this.value)
+ // 查询职务信息
+ queryPositionInfo() {
+ getAction(this.url.listByPosition, { pageSize: 99999 }).then(res => {
+ let positionInfo = {}
+ res.result.records.forEach(record => {
+ positionInfo[record['code']] = record['name']
+ this.positionInfo = positionInfo
+ .j-address-list-right-card-box .ant-table-placeholder {
+ min-height: 46px;
+ .j-address-list-right-card-box {
+ height: 100%;
+ min-height: 300px;
+ label="规则名称">
+ <a-input placeholder="请输入规则名称" v-decorator="['ruleName', validatorRules.ruleName]"/>
+ label="规则Code">
+ <a-input placeholder="请输入规则Code" :disabled="disabledCode" v-decorator="['ruleCode', validatorRules.ruleCode]"/>
+ label="规则实现类">
+ <a-input placeholder="请输入规则实现类" v-decorator="['ruleClass', validatorRules.ruleClass]"/>
+ label="规则参数">
+ <a-textarea placeholder="请输入规则参数" :rows="5" v-decorator="['ruleParams', validatorRules.ruleParams]"/>
+ import { validateDuplicateValue } from '@/utils/util'
+ name: 'SysFillRuleModal',
+ labelCol: { xs: { span: 24 }, sm: { span: 5 } },
+ wrapperCol: { xs: { span: 24 }, sm: { span: 16 } },
+ validatorRules: {
+ ruleName: { rules: [{ required: true, message: '规则名称不能为空' }] },
+ ruleCode: {
+ rules: [
+ { required: true, message: '规则Code不能为空' },
+ { validator: (rule, value, callback) => validateDuplicateValue('sys_fill_rule', 'rule_code', value, this.model.id, callback) }
+ ruleClass: { rules: [{ required: true, message: '规则实现类不能为空' }] },
+ ruleParams: {
+ rules: [{
+ validator: (rule, value, callback) => {
+ let json = JSON.parse(value)
+ if (json instanceof Array) {
+ callback('只能传递JSON对象,不能传递JSON数组')
+ } else if (json instanceof Object) {
+ callback('请输入JSON字符串')
+ } catch {
+ add: '/sys/fillRule/add',
+ edit: '/sys/fillRule/edit',
+ disabledCode() {
+ return !!this.model.id
+ add() {
+ this.edit({})
+ edit(record) {
+ this.form.resetFields()
+ this.model = Object.assign({}, record)
+ this.form.setFieldsValue(pick(this.model, 'ruleName', 'ruleCode', 'ruleClass', 'ruleParams'))
+ this.$emit('close')
+ const that = this
+ that.confirmLoading = true
+ let httpUrl = this.url.add, method = 'post'
+ if (this.model.id) {
+ httpUrl = this.url.edit
+ method = 'put'
+ let formData = Object.assign(this.model, values)
+ httpAction(httpUrl, formData, method).then((res) => {
+ that.$message.success(res.message)
+ that.$emit('ok')
+ that.confirmLoading = false
+ that.close()
+ handleCancel() {
@@ -0,0 +1,180 @@
+ label="职务编码">
+ <a-input placeholder="请输入职务编码" v-decorator="['code', validatorRules.code]"/>
+ label="职务名称">
+ <a-input placeholder="请输入职务名称" v-decorator="['name', validatorRules.name]"/>
+ label="职级"
+ <j-dict-select-tag
+ placeholder="请选择职级"
+ :triggerChange="true"
+ dictCode="position_rank"
+ v-decorator="['postRank', validatorRules.postRank]"
+ <!--<a-form-item-->
+ <!-- :labelCol="labelCol"-->
+ <!-- :wrapperCol="wrapperCol"-->
+ <!-- label="公司id">-->
+ <!-- <a-input placeholder="请输入公司id" v-decorator="['companyId', {}]"/>-->
+ <!--</a-form-item>-->
+ import { duplicateCheck } from '@/api/api'
+ let validatorCodeTimer = null
+ name: 'SysPositionModal',
+ components: { JDictSelectTag },
+ code: {
+ { required: true, message: '请输入职务编码' },
+ // 函数消抖的简单实现,防止一段时间内发送多次请求
+ if (validatorCodeTimer) {
+ // 停止上次开启的定时器
+ clearTimeout(validatorCodeTimer)
+ validatorCodeTimer = setTimeout(() => {
+ duplicateCheck({
+ tableName: 'sys_position',
+ fieldName: 'code',
+ fieldVal: value,
+ dataId: this.model.id
+ callback(res.message)
+ }).catch(console.error)
+ }, 300)
+ name: { rules: [{ required: true, message: '请输入职务名称' }] },
+ postRank: { rules: [{ required: true, message: '请选择职级' }] },
+ add: '/sys/position/add',
+ edit: '/sys/position/edit',
+ this.form.setFieldsValue(pick(this.model,
+ 'code',
+ 'name',
+ 'postRank',
+ // 'companyId'
+ ))
+ let httpurl = ''
+ let method = ''
+ if (!this.model.id) {
+ httpurl += this.url.add
+ method = 'post'
+ httpurl += this.url.edit
+ httpAction(httpurl, formData, method).then((res) => {
@@ -69,7 +69,7 @@ module.exports = {
target: 'http://192.168.2.143:8080', //请求本地 需要jeecg-boot后台项目 蒙蒙
// target: 'http://192.168.2.133:8080', //请求本地 需要jeecg-boot后台项目 英豪
// target: 'http://192.168.2.132:8080', //请求本地 需要jeecg-boot后台项目
- // target: 'http://192.168.2.174:8080', //请求本地 需要jeecg-boot后台项目 祚云
+ // target: 'http://192.168.2.115:8080', //请求本地 需要jeecg-boot后台项目 祚云
// target: 'http://192.168.2.132:8080', //请求本地 需要jeecg-boot后台项目 孙震
ws: false,