| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564 |
- <template>
- <div id="singleDataTableManager">
- <div :style="{'max-height':heightForDialog + 'px'}" style="padding: 10px;width:100%;background-color:white;overflow-y: auto;">
- <el-form ref="form" label-width="160px" >
- <!-- form表单填录项配置 -->
- <el-form-item
- v-for="formItem in formItems"
-
- :key="formItem.mainItem.label"
- >
- <template name="label" slot="label"><!--2018.09.16 增加对必填项目的星号提示-->
- <p style="display:inline;color:red" v-if="formItem.mainItem.isRequired" v-show="!formItem.mainItem.isHidden">*</p>
- <p style="display:inline;" v-show="!formItem.mainItem.isHidden">{{formItem.mainItem.label}}:</p>
- </template>
- <el-row :gutter="20">
- <!--总共以row作为一行的分割,靠 -->
- <el-col :span="formItem.mainItem.type == 'richtext'?20:9">
-
- <el-input v-if="formItem.mainItem.type != 'table'
- &&formItem.mainItem.type != 'date'
- &&formItem.mainItem.type != 'month'
- &&formItem.mainItem.type != 'select'
- &&formItem.mainItem.type != 'tree'
- &&formItem.mainItem.type != 'table'
- &&formItem.mainItem.type != 'treeCheck'
- &&formItem.mainItem.type != 'selectMultiple'
- &&formItem.mainItem.type != 'richtext'
- &&formItem.mainItem.type != 'year'"
- :type="formItem.mainItem.type=='textarea'?'textarea':
- formItem.mainItem.type=='password' ? 'password' : 'text'"
- v-model="formDataObject[formItem.mainItem.prop]"
- v-show="!formItem.mainItem.isHidden">
- </el-input>
-
-
-
- <el-date-picker v-if="formItem.mainItem.type=='date'||formItem.mainItem.type=='year'||formItem.mainItem.type=='month'"
- v-show="!formItem.mainItem.isHidden"
- :type="formItem.mainItem.type=='date'?'date':formItem.mainItem.type=='year' ? 'year':formItem.mainItem.type=='month' ? 'month':'date'"
- v-model="formDataObject[formItem.mainItem.prop]"
- :value-format="formItem.mainItem.type=='date' ? 'yyyy-MM-dd':formItem.mainItem.type=='month' ? 'yyyy-MM':'yyyy'"></el-date-picker>
- <!--<el-date-picker type="year" v-if="formItem.type=='year'" v-model="formDataObject[formItem.prop]"></el-date-picker>-->
- <el-select-dict v-if="formItem.mainItem.type=='select'" v-show="!formItem.mainItem.isHidden" :dictId="formItem.mainItem['refObjValue']" v-model="formDataObject[formItem.mainItem.prop]"></el-select-dict>
- <el-multiple-select v-if="formItem.mainItem.type=='selectMultiple'" v-show="!formItem.mainItem.isHidden" @privInfo='infoList' :id="idid"></el-multiple-select>
- <Editor id="condition" v-if="formItem.mainItem.type=='richtext'" v-show="!formItem.mainItem.isHidden" v-model="formDataObject[formItem.mainItem.prop]" :init="editorInit"></Editor>
-
- </el-col>
- <el-col :offset="1" :span="formItem.subItem.length>0?9:2" >
- <div class="subFormItem" style="display:flex;"
- v-for="subFormItem in formItem.subItem" v-show="!subFormItem.isHidden" :key="subFormItem.prop" >
- <el-row :gutter="20">
- <el-col :offset="2" :span="8">
- <p style="display:inline;color:red" v-if="subFormItem.isRequired">*</p>
- <p style="display:inline;">{{subFormItem.label}}:</p>
- </el-col>
- <el-col :span="12">
- <el-input v-if="subFormItem.type!='table'
- &&subFormItem.type !='date'
- &&subFormItem.type !='month'
- &&subFormItem.type !='select'
- &&subFormItem.type != 'tree'
- &&subFormItem.type != 'table'
- &&subFormItem.type != 'treeCheck'
- &&subFormItem.type != 'selectMultiple'
- &&subFormItem.type != 'richtext'
- &&subFormItem.type != 'year'"
- :type="subFormItem.type=='textarea'?'textarea':
- subFormItem.type=='password' ? 'password' : 'text'"
- v-model="formDataObject[subFormItem.prop]">
- </el-input>
- </el-col>
- <!-- </span> -->
- </el-row>
- </div>
- </el-col>
- <!-- <el-col :span="6"><div class="grid-content bg-purple"></div></!-->
- <el-col :span="formItem.subAction.length>0?4:8" >
- <el-button v-for="action in formItem.subAction" :key="action.name" v-show="!action.isHidden">{{action.label}}</el-button>
- </el-col>
- </el-row>
- </el-form-item>
- <!-- form表单操作项配置 -->
- </el-form>
- </div>
- <el-row style="text-align: right;margin-top: 25px;">
- <el-button v-for="action in bottomActions" :key="action.name" :type="action.label =='保存'?'primary':''"
- @click="handleFormAction(action)"
-
- >{{action.label}}</el-button>
- </el-row>
-
-
- </div>
- </template>
- <script>
- /*
- 组件名称:simpleDataTable
- 组件用途:结合基础组件、查询条件的可配置表格,基于singleDataManager拆分而来。独立用于展示,并且可通过与simpleDataForm组合构成原有的singleDataManager
- 依赖组件:
- axios - ajax请求
- @tinymce/tinymce-vue - 富文本编辑
- 包含API文件:
- (dictionaryApi - 字典相关的API)
- props:tableViewId:string - 指定管理视图代码 (通过此代码查询接口获得组成页面的所有信息)
- otherParamsObject:object - 额外查询参数(为有额外联查条件要求准备,所有属性均会附加在所有请求中)
- 版本记录:
- 0.0.1 (初版) @author:wxcwater @date:2019.06.24
-
- */
- import axios from 'axios';
- import tinymce from 'tinymce/tinymce'
- import 'tinymce/themes/silver/theme'
- import Editor from '@tinymce/tinymce-vue'
- import 'tinymce/plugins/image'
- import 'tinymce/plugins/link'
- import 'tinymce/plugins/code'
- import 'tinymce/plugins/table'
- import 'tinymce/plugins/lists'
- import 'tinymce/plugins/contextmenu'
- import 'tinymce/plugins/wordcount'
- import 'tinymce/plugins/colorpicker'
- import 'tinymce/plugins/textcolor'
- import {getAddTree} from '../api/administrativeRegion.js'
- import request from '../utils/gw_ajax_request.js'
- import {dateFormat} from '../utils/gw_date.js'
- import {getdictItemBydictIdSync} from '../utils/gw_dictionary.js'
- import elSelectDict from './elSelectWithDict.vue'
- import elMultipleSelect from './selectMultiple.vue'
- export default {
- props:['tableViewConfig','tableViewId','dataTitle','otherParamsObject','requestUrl','formData'],
- name: 'singleDataTableManager',
- components: {
- 'el-select-dict':elSelectDict,
- 'el-multiple-select': elMultipleSelect,
- 'Editor':Editor,
- },
- computed:{
- },
- watch:{
- formDataObject:{
- handler(){
- console.log('formDataObject变化了');
- this.pollingFormLogic();//计算逻辑
- },
- deep:true,
- },
- formData:function(){
- this.formDataObject = this.formData;
- },
-
- otherParamsObject:{
- handler(){
- console.log('otherParamsObject');
- this.getFormData();
- },
- deep:true,
- }
- },
- data () {
- return {
- heightForDialog:window.innerHeight*0.45,
-
- mainHeight:window.innerHeight-265,
- manageViewConfigure:{},//从后台获得的view整体的配置信息对象
- viewActions:[],//脱离于table与form的操作 如刷新、查询等
- tableViewConfigure:[],//table表格的数据列配置
- tableColumnsActions:[],//table表格每行的操作 如 查询 修改 删除
- formViewConfigure:[],//form表单的配置对象
- bottomActions:[],//form表单的操作 如 保存 取消
-
-
- formLogicObject:{},
- formBasicObject:{},//表单基本对象
- formDataObject:{},//表单数据对象(实际持有表单数据的对象)
- actionType:'',//针对表单 是修改(edit) 或是 新增(add) 的状态记录
-
-
- baseUrl:'',
-
-
-
- formItems:[],
-
- editorInit: {//富文本编辑器插件需要的配置
- selector: 'condition',
- language_url: '/static/tinymce/zh_CN.js',
- language: 'zh_CN',
- skin_url: '/static/tinymce/skins/ui/oxide',
- height: 300,
- plugins: 'link image wordcount',
- toolbar:'bold italic underline strikethrough | link unlink image | removeformat',
- branding: false
- },
- }
- },
- mounted:function(){
- let me = this;
- tinymce.init({});
- me.getManageViewConfigureInformation();
- console.log(this.otherParamsObject);
- },
- activated(){
-
- tinymce.init({});
- this.getManageViewConfigureInformation();
- console.log(this.otherParamsObject);
- },
- methods:{
-
-
- getManageViewConfigureInformation:function(){ //通过tableViewId
- // console.log('获取'+this.tableViewId+'的配置内容');
- let _self = this;
- let getConfigType = typeof this.tableViewConfig;
- if(getConfigType == 'object'){
- _self.manageViewConfigure =this.tableViewConfig;
- this.analyseManageViewConfigure();
- }
- // if(this.tableViewConfig){
- // _self.manageViewConfigure = res.data[_self.tableViewId];
- // // _self.dataTitle.title = res.data[_self.tableViewId].title;
- // this.analyseManageViewConfigure();
- // }else{
- // axios.get('/src/static/fields.json').then((res) => {
- // _self.manageViewConfigure = res.data[_self.tableViewId];
- // // _self.dataTitle.title = res.data[_self.tableViewId].title;
- // this.analyseManageViewConfigure();
- // })
- // }
-
- },
- analyseUrlTempLateToRealUrl:function(urlTemplate,paramsObject){
- let urlTemp = urlTemplate.split('/');
- urlTemp.forEach((element,index) => {
- if(element.startsWith('{')&&element.endsWith('}')){
- console.log('换'+paramsObject[element.substring(1,element.length-1)]);
- urlTemp[index] = paramsObject[element.substring(1,element.length-1)]
- }
- });
- console.log(urlTemp);
- return this.baseUrl + urlTemp.join('/');
- },
- analyseManageViewConfigure:function(){
-
- let _self = this;
- let getConfigType = typeof this.tableViewConfig;
- if(getConfigType == 'object'){//如果props里的tableViewConfig是object认为给的就是配置对象了,还考虑function与promise的类型 后续添加
- _self.manageViewConfigure =this.tableViewConfig;
- this.analyseManageViewConfigure();//开始分析解析配置文件
- }
- },
- analyseManageViewConfigure:function(){//分析配置文件,生成一些基本对象
- let _self = this;
- let fields = [];//fields为组件的数据配置,产生影响的包括table的列与一些查询、排序等的内容
- let actions = [];//actions为组件的操作配置,产生影响的包括一些button等的方法。
- let formItems = [];//由于有同行关联的填报项目,需要将fields
- let formLogics = [];//用于暂存表单规则
- let formItemKeySet = new Set();
- if(this.manageViewConfigure && this.manageViewConfigure.hasOwnProperty('fields')){
- fields = this.manageViewConfigure['fields'];
- this.formViewConfigure = fields;//存到tableViewConfigure里方便模板使用
- }
- if(this.manageViewConfigure && this.manageViewConfigure.hasOwnProperty('actions')){
- actions = this.manageViewConfigure['actions'];
- }
- if(this.manageViewConfigure && this.manageViewConfigure.hasOwnProperty('logics')){
- formLogics = this.manageViewConfigure['logics'];
- }
- //wxcwater 2019.07.11 对fields进行遍历 匹配formItems供template使用
- fields.forEach((field)=>{
- if(field.hasOwnProperty('position')&&field['position']){
- let fieldKey = field['position'];
- //默认如果一个field的position指向其他field的prop说明这个填报项是依赖于其他填报项的附属项目,如因为其他项目的填报计算而得的小分等
- //默认附属填报项目与填报项目同行。所以有些显隐依赖但是换行的 请不要设置position
- if(formItemKeySet.has(fieldKey)){//判断是否已经有主项
- //如果存在主项目再轮询formItems找到主项目并插入到附属项目中
- formItems.forEach((fromItem)=>{
- if(fromItem.itemKey == fieldKey){
- fromItem.subItem.push(field);
- }
- });
- }else{
- // 如果暂时还没有主项目就设置主项目
- let itemKey = field['position'];
- let newFormItemWithSubItem = {
- itemKey:itemKey,
- mainItem:null,
- subItem:[field],
- subAction:[],
- };
- formItems.push(newFormItemWithSubItem);
- formItemKeySet.add(itemKey);
- }
- }else{
- //没有position或者position不是其他填报项目的,代表这是一个主填报项目
- let fieldKey = field['prop'];//对于主要项目 prop属性是唯一的key
- if(formItemKeySet.has(fieldKey)){//判断是否已经有此主项
- //有说明重复
- }else{
- // 如果暂时还没有主项目就设置主项目
- let newFormItemWithMainItem = {
- itemKey:fieldKey,
- mainItem:field,
- subItem:[],
- subAction:[],
- };
- formItems.push(newFormItemWithMainItem);
- formItemKeySet.add(fieldKey);
- }
- }
- });
- console.log('生成formItems');
- actions.forEach(item => {//对actions进行细分,根据每个action的position属性确定action代表的button是在组件的位置(outer:table外,在查询部分,inner:在table的每行中)
- if(item.position=='bottom'){ //bottom(目前只开放下部)说明一般是表单外部按钮,一般是保存提交一类的
- this.bottomActions.push(item);
- }else if(formItemKeySet.has(item.position)){
- let actionKey = item.position;
- //如果position是fields中的一项(关联主项)则说明是行内按钮。一般表征为 针对某个填报项目提问题的按钮。
- formItems.forEach((fromItem)=>{
- if(fromItem.itemKey == actionKey){
- fromItem.subAction.push(item);
- }
- });
- }
- });
- console.log('向表单追加行内关联的action');
- this.formItems = formItems;
- formLogics.forEach((logic)=>{
- //循环设置对象。待对象变动后重新执行
- if(logic.hasOwnProperty('prop')){
- if(this.formLogicObject[logic['prop']]){
- this.formLogicObject[logic['prop']].push(logic);
- }else{
- this.formLogicObject[logic['prop']] = [logic];
- }
- }
- });
- //以上配置的赋值会影响页面绘制,故绘制完再进行实体数据的获取
-
- this.formViewConfigure.forEach(item => {//设定form表单基本对象
- this.formBasicObject[item.prop] = null;
- if(item.hasOwnProperty('defaultValue')&&item['defaultValue']){
- _self.formBasicObject[item.prop] = item['defaultValue'];
- }
- });
- this.formDataObject = Object.assign({},_self.formBasicObject); //克隆basic对象,防止后续对BasicObject的污染
-
- this.$nextTick(function(){
- _self.getFormData();
- });
-
-
- console.log('打印结果');
- console.log(this.viewActions);
- console.log(this.tableColumnsActions);
- console.log(this.bottomActions);
-
- },
- getFormData:function(){//获取表单原始数据
- let _self = this;
-
- //form既有数据的获取有两种情况,1是外部直接赋值进来对象,2是赋值url根据特定key进行请求
- //如果有form对象应当处理为编辑,如果没有form对象应该处理成请求
- let formType = 'add';//默认是添加逻辑
- if(_self.formData && (typeof _self.formData == 'object')){
- formType = 'edit';
- _self.formDataObject = _self.formData;
- this.formViewConfigure.forEach(item => {//设定form表单基本对象
- this.formBasicObject[item.prop] = null;
- if(item.hasOwnProperty('type')&&item['type']=='date'){
- _self.formDataObject[item.prop] = new Date(_self.formDataObject[item.prop]);
- }
- });
- }else if(_self.formData && (typeof _self.formData == 'string')){//to-d0:需要增加验证是否为url
- formType = 'edit';
- let queryParams = {};
- if(th_selfis.otherParamsObject){
- queryParams = Object.assign(queryParams, _self.otherParamsObject);
- }
- request({
- url: _self.formData,
- method: _self.searchType?_self.searchType:'POST',
- params: queryParams
- }).then((response) => {
- _self.formDataObject = response.data.data ? response.data.data : response.data
- }).catch(function (err) {
- console.log(err);
- });
- }else{
- //什么都没有考虑是新郑逻辑
- formType = 'add';
- this.formDataObject = Object.assign({},this.formBasicObject); //克隆basic对象,防止后续对BasicObject的污染
-
- }
-
- },
-
-
- handleFormAction:function(formaction){
- this.$emit('formActionClick',{'formData':this.formDataObject,'action':formaction});
- let action = formaction.action;//获取action的动作类型
- let _self = this;
- // 判断是否为组件内部方法,如果是可以直接调用。考虑通过|操作符对多个动作进行连接。
- if(this.hasOwnProperty(action) && (typeof this[action]) == "function"){
- //如果有同名内部方法就直接调用,为了是查询等操作可以直接使用loadData等
- console.log('innerAction调用内部方法');
- this[action]();
- }else if(action == 'request'){
- // 如果是request类型的 默认为发送请求类的动作。目前主要是 删除 等。删除完需要同步刷新数据
- let realUrl = this.analyseUrlTempLateToRealUrl(formaction.url,this.formDataObject);//如果是restful的会按照模板进行处理,没有就不处理了
- let queryParams = this.formDataObject;
- if(this.otherParamsObject) {
- queryParams= this.otherParamsObject;
- }
- let requestType = formaction.hasOwnProperty('requestType')&&formaction['requestType'] != ''?formaction['requestType']:'POST';
- //获取请求类型,默认是GET
- request({
- url: realUrl,
- method: requestType,
- params: queryParams,//考虑接口差异,data、params都传递
- data: queryParams//考虑接口差异,data、params都传递
- }).then((response) => {
- _self.$emit('formActionFinished',{});
- })
- }
- },
- pollingFormLogic:function(){
- //每次监测到formDataObject变化都要调用此方法,来统一轮询逻辑(formLogic)并且将相应的逻辑体现出来
- let _self = this;
- //对渲染模板使用的formItems做轮询,查看各个属性是否需要逻辑计算
- _self.formItems.forEach((formItem)=>{
- // 查看一个表单行的主要元素是否有逻辑
- if(_self.formLogicObject.hasOwnProperty(formItem.mainItem.prop)){
- _self.applyLogic(formItem.mainItem,_self.formLogicObject[formItem.mainItem.prop]);
- }
- // 查看是否有附属填报项目,如果有轮询附属填报项目查看是否有逻辑
- if(formItem.subItem.length>0){
- formItem.subItem.forEach((subItem)=>{
- if(_self.formLogicObject.hasOwnProperty(subItem.prop)){
- _self.applyLogic(subItem,_self.formLogicObject[subItem.prop]);
- }
- })
- }
- // 查看是否有附属惭怍,如果有附属操作轮询附属操作查看是否有逻辑
- if(formItem.subAction.length>0){
- formItem.subAction.forEach((subAction)=>{
- if(_self.formLogicObject.hasOwnProperty(subAction.name)){
- _self.applyLogic(subAction,_self.formLogicObject[subAction.name]);
- }
- })
- }
- });
-
- },
- applyLogic:function(targetItem,logicItem){
- logicItem.forEach((logic) => {
- if(logic.logic=='visible'){
- targetItem.isHidden = !this.applyRule(logic.rule);//因为是isHidden所以取反
- }else if(logic.logic=='value'){
- this.formDataObject[targetItem.prop] = this.applyRule(logic.rule);
- }else if(logic.logic=='option'){
- //to-do 根据其他值改变某些select的options
- }
- });
-
- },
- applyRule:function(rule){//有可能的返回:数字结果、布尔值、null(null表示错误)
- let logicalOperator = ['==','&&','||','?','>','<','>=','<=','?',':'];//目前应当支持的逻辑操作符
- let mathematicsOperator = ['+','-','*','/','%'];//目前应当支持的数学计算操作符
- let _self = this;
- //rule目前考虑对简单的逻辑、数学运算进行计算。不同单元请以空格隔开。
- // 优先判断是否包含三元表达式,包含表达式的会被拆分成更小单位的rule,数学表达式由于可能出现(),所以要转换成后缀表达式才能求值。
- /* 考虑(a==b?1:0)*2
- a==b?b==c?0:1:2
- a+b*c
- (a+b)*c
- a+b==2?0:1
- 自己解表达式有点麻烦,用eval试试
- */
- let ruleArray = rule.split(' ');
- console.log(ruleArray);
- let evalString = '';
- ruleArray.forEach((unit)=>{
- if(logicalOperator.indexOf(unit)<0&&mathematicsOperator.indexOf(unit)&&unit!=''&&unit!=' '&&Number.isNaN(Number(unit))&&unit.indexOf("'")<0){
- //不包含逻辑符号也不包含数学符号也不为空或者空格说明应当是一个变量
- evalString+='this.formDataObject.' + unit;
- }else{
- evalString+=unit;
- }
- });
- console.log('evalString:'+evalString);
- let result = eval(evalString);
- console.log('evalStringresult:'+result);
- return result;
- },
- countLogical:function(rule){
- // 计算普通逻辑表达式
- },
- countMathematics:function(rule){
- // 计算普通数学表达式
- }
- }
- }
- </script>
- <style>
- #singleDataTableManager{
- /*height:100%;*/
- width:100%;
- /* margin:-15px; */
- }
- #singleDataTableManager th,#singleDataTableManager .el-table thead tr {
- font-size: 14px;
- background-color: #eef1f6;
- color: #1f2d3d;
- }
- .searchPanel{
- width:100%;
- /* border-bottom: 1px dotted #6161d7; */
- /* padding-bottom:10px; */
- padding-left: 10px;
- margin-top: 10px;
- box-sizing: border-box;
- /* overflow: hidden; */
- }
- .actionPanel{
- width:100%;
- }
- .searchPanel .el-form{
- float: left;
- margin-right: 20px;
- height: 30px;
- }
- #singleDataTableManager .pagination{
- text-align: center;
- }
- #singleDataTableManager .el-select{
- width: 100%;
- }
- .menu_tree .el-tree-node__content .el-tree-node__expand-icon+span::before {
- content: url(../assets/images/place.png);
- margin-right: 6px;
- }
- .menu_tree .el-tree-node__children .el-tree-node__expand-icon+span::before {
- content: url(../assets/images/place.png);
- }
- </style>
|