Merge remote-tracking branch 'origin/dev' into dev
						commit
						815b8e956b
					
				|  | @ -366,14 +366,17 @@ CAPTCHA_CHALLENGE_FUNCT = "captcha.helpers.math_challenge"  # 加减乘除验证 | |||
| # ================================================= # | ||||
| 
 | ||||
| DEFAULT_AUTO_FIELD = "django.db.models.AutoField" | ||||
| API_LOG_ENABLE = True | ||||
| # 是否启动API日志记录 | ||||
| API_LOG_ENABLE = locals().get("API_LOG_ENABLE", True) | ||||
| # API 日志记录的请求方式 | ||||
| API_LOG_METHODS = locals().get("API_LOG_METHODS", ["POST", "UPDATE", "DELETE", "PUT"]) | ||||
| # API_LOG_METHODS = 'ALL' # ['POST', 'DELETE'] | ||||
| API_LOG_METHODS = ["POST", "UPDATE", "DELETE", "PUT"]  # ['POST', 'DELETE'] | ||||
| API_MODEL_MAP = { | ||||
| # 在操作日志中详细记录的请求模块映射 | ||||
| API_MODEL_MAP = locals().get("API_MODEL_MAP", { | ||||
|     "/token/": "登录模块", | ||||
|     "/api/login/": "登录模块", | ||||
|     "/api/plugins_market/plugins/": "插件市场", | ||||
| } | ||||
|     "/api/logout/": "登录模块", | ||||
| }) | ||||
| 
 | ||||
| DJANGO_CELERY_BEAT_TZ_AWARE = False | ||||
| CELERY_TIMEZONE = "Asia/Shanghai"  # celery 时区问题 | ||||
|  |  | |||
|  | @ -39,6 +39,11 @@ DEBUG = True | |||
| ENABLE_LOGIN_ANALYSIS_LOG = True | ||||
| # 登录接口 /api/token/ 是否需要验证码认证,用于测试,正式环境建议取消 | ||||
| LOGIN_NO_CAPTCHA_AUTH = True | ||||
| # 是否启动API日志记录 | ||||
| API_LOG_ENABLE = locals().get("API_LOG_ENABLE", True) | ||||
| # API 日志记录的请求方式 | ||||
| API_LOG_METHODS = locals().get("API_LOG_METHODS", ["POST", "UPDATE", "DELETE", "PUT"]) | ||||
| # API_LOG_METHODS = 'ALL' # ['POST', 'DELETE'] | ||||
| # ================================================= # | ||||
| # ****************** 其他 配置  ******************* # | ||||
| # ================================================= # | ||||
|  |  | |||
|  | @ -21,18 +21,21 @@ class FileSerializer(CustomModelSerializer): | |||
|         fields = "__all__" | ||||
| 
 | ||||
|     def create(self, validated_data): | ||||
|         file_engine = dispatch.get_system_config_values("fileStorageConfig.file_engine") | ||||
|         file_engine = dispatch.get_system_config_values("fileStorageConfig.file_engine") or 'local' | ||||
|         file_backup = dispatch.get_system_config_values("fileStorageConfig.file_backup") | ||||
|         file = self.initial_data.get('file') | ||||
|         file_size = file.size | ||||
|         validated_data['name'] = file.name | ||||
|         validated_data['size'] = file_size | ||||
|         validated_data['md5sum'] = hashlib.md5().hexdigest() | ||||
|         md5 = hashlib.md5() | ||||
|         for chunk in file.chunks(): | ||||
|             md5.update(chunk) | ||||
|         validated_data['md5sum'] = md5.hexdigest() | ||||
|         validated_data['engine'] = file_engine | ||||
|         validated_data['mime_type'] = file.content_type | ||||
|         if file_backup: | ||||
|             validated_data['url'] = file | ||||
|         if file_engine =='oss': | ||||
|         if file_engine == 'oss': | ||||
|             from dvadmin_cloud_storage.views.aliyun import ali_oss_upload | ||||
|             file_path = ali_oss_upload(file) | ||||
|             if file_path: | ||||
|  |  | |||
|  | @ -21,9 +21,9 @@ def import_to_data(file_url, field_data, m2m_fields=None): | |||
|     file_path_dir = os.path.join(settings.BASE_DIR, file_url) | ||||
|     workbook = openpyxl.load_workbook(file_path_dir) | ||||
|     table = workbook[workbook.sheetnames[0]] | ||||
|     theader = tuple(table.values)[0] #Excel的表头 | ||||
|     is_update = '更新主键(勿改)' in theader #是否导入更新 | ||||
|     if is_update is False: #不是更新时,删除id列 | ||||
|     theader = tuple(table.values)[0]  # Excel的表头 | ||||
|     is_update = '更新主键(勿改)' in theader  # 是否导入更新 | ||||
|     if is_update is False:  # 不是更新时,删除id列 | ||||
|         field_data.pop('id') | ||||
|     # 获取参数映射 | ||||
|     validation_data_dict = {} | ||||
|  | @ -35,9 +35,10 @@ def import_to_data(file_url, field_data, m2m_fields=None): | |||
|                 for k, v in choices.get("data").items(): | ||||
|                     data_dict[k] = v | ||||
|             elif choices.get("queryset") and choices.get("values_name"): | ||||
|                 data_list = choices.get("queryset").values(choices.get("values_name"), "id") | ||||
|                 data_list = choices.get("queryset").values(choices.get("values_name"), | ||||
|                                                            choices.get("values_value", "id")) | ||||
|                 for ele in data_list: | ||||
|                     data_dict[ele.get(choices.get("values_name"))] = ele.get("id") | ||||
|                     data_dict[ele.get(choices.get("values_name"))] = ele.get(choices.get("values_value", "id")) | ||||
|             else: | ||||
|                 continue | ||||
|             validation_data_dict[key] = data_dict | ||||
|  | @ -53,12 +54,11 @@ def import_to_data(file_url, field_data, m2m_fields=None): | |||
|             values = items[1] | ||||
|             value_type = 'str' | ||||
|             if isinstance(values, dict): | ||||
|                 value_type = values.get('type','str') | ||||
|                 value_type = values.get('type', 'str') | ||||
|             cell_value = table.cell(row=row + 1, column=index + 2).value | ||||
|             if cell_value is None or cell_value=='': | ||||
|             if cell_value is None or cell_value == '': | ||||
|                 continue | ||||
|             elif value_type == 'date': | ||||
|                 print(61, datetime.strptime(str(cell_value), '%Y-%m-%d %H:%M:%S').date()) | ||||
|                 try: | ||||
|                     cell_value = datetime.strptime(str(cell_value), '%Y-%m-%d %H:%M:%S').date() | ||||
|                 except: | ||||
|  | @ -66,7 +66,7 @@ def import_to_data(file_url, field_data, m2m_fields=None): | |||
|             elif value_type == 'datetime': | ||||
|                 cell_value = datetime.strptime(str(cell_value), '%Y-%m-%d %H:%M:%S') | ||||
|             else: | ||||
|             # 由于excel导入数字类型后,会出现数字加 .0 的,进行处理 | ||||
|                 # 由于excel导入数字类型后,会出现数字加 .0 的,进行处理 | ||||
|                 if type(cell_value) is float and str(cell_value).split(".")[1] == "0": | ||||
|                     cell_value = int(str(cell_value).split(".")[0]) | ||||
|                 elif type(cell_value) is str: | ||||
|  |  | |||
|  | @ -1,4 +1,5 @@ | |||
| # -*- coding: utf-8 -*- | ||||
| from types import FunctionType, MethodType | ||||
| from urllib.parse import quote | ||||
| 
 | ||||
| from django.db import transaction | ||||
|  | @ -68,6 +69,8 @@ class ImportSerializerMixin: | |||
|         :return: | ||||
|         """ | ||||
|         assert self.import_field_dict, "'%s' 请配置对应的导出模板字段。" % self.__class__.__name__ | ||||
|         if isinstance(self.import_field_dict, MethodType) or isinstance(self.import_field_dict, FunctionType): | ||||
|             self.import_field_dict = self.import_field_dict() | ||||
|         # 导出模板 | ||||
|         if request.method == "GET": | ||||
|             # 示例数据 | ||||
|  | @ -160,6 +163,8 @@ class ImportSerializerMixin: | |||
|         assert self.import_field_dict, "'%s' 请配置对应的导入模板字段。" % self.__class__.__name__ | ||||
|         assert self.import_serializer_class, "'%s' 请配置对应的导入序列化器。" % self.__class__.__name__ | ||||
|         data = self.import_serializer_class(queryset, many=True, request=request).data | ||||
|         if isinstance(self.import_field_dict, MethodType) or isinstance(self.import_field_dict, FunctionType): | ||||
|             self.import_field_dict = self.import_field_dict() | ||||
|         # 导出excel 表 | ||||
|         response = HttpResponse(content_type="application/msexcel") | ||||
|         response["Access-Control-Expose-Headers"] = f"Content-Disposition" | ||||
|  |  | |||
|  | @ -44,6 +44,7 @@ | |||
|     "vue": "2.7.14", | ||||
|     "vue-echarts": "^6.5.4", | ||||
|     "vue-grid-layout": "^2.4.0", | ||||
|     "vue-html2pdf": "^1.8.0", | ||||
|     "vue-i18n": "^8.15.1", | ||||
|     "vue-infinite-scroll": "^2.0.2", | ||||
|     "vue-router": "^3.6.5", | ||||
|  |  | |||
										
											
												File diff suppressed because one or more lines are too long
											
										
									
								
							|  | @ -0,0 +1,176 @@ | |||
| <template> | ||||
|   <div> | ||||
|     <div style="position: absolute;z-index: 10000"> | ||||
|       <el-button | ||||
|         type="success" | ||||
|         round | ||||
|         size="small" | ||||
|         v-if="downloadButtonShow" | ||||
|         :style="downloadButtonStyle" | ||||
|         @click="generateReport" | ||||
|         :loading="downloadLoading" | ||||
|       >{{ downloadButtonTitle }} | ||||
|       </el-button> | ||||
|       <el-button | ||||
|         type="primary" | ||||
|         round | ||||
|         size="small" | ||||
|         v-if="previewButtonShow" | ||||
|         style="position: fixed; right: 50px; bottom: 70px" | ||||
|         @click="previewPdf" | ||||
|         :loading="previewLoading" | ||||
|       >{{ previewButtonTitle }} | ||||
|       </el-button> | ||||
|     </div> | ||||
|     <vue-html2pdf | ||||
|       :show-layout="true" | ||||
|       :float-layout="false" | ||||
|       :enable-download="false" | ||||
|       :preview-modal="preview" | ||||
|       :filename="filename" | ||||
|       :paginate-elements-by-height="1100" | ||||
|       :pdf-quality="2" | ||||
|       pdf-format="a4" | ||||
|       pdf-orientation="portrait" | ||||
|       pdf-content-width="100%" | ||||
|       :manual-pagination="true" | ||||
|       :html-to-pdf-options="{ margin: [5, 5, 0, 5] }" | ||||
|       @beforeDownload="beforeDownload($event)" | ||||
|       ref="html2Pdf" | ||||
|     > | ||||
|       <section slot="pdf-content"> | ||||
|         <slot></slot> | ||||
|       </section> | ||||
|     </vue-html2pdf> | ||||
|   </div> | ||||
| </template> | ||||
| 
 | ||||
| <script> | ||||
| import SongtiSCBlack from '@/assets/fonts/SongtiSCBlack' | ||||
| import VueHtml2pdf from 'vue-html2pdf' | ||||
| 
 | ||||
| export default { | ||||
|   name: 'dvaHtml2pdf', | ||||
|   components: { | ||||
|     VueHtml2pdf | ||||
|   }, | ||||
|   props: { | ||||
|     filename: { // 导出pdf文件名称 | ||||
|       type: String, | ||||
|       require: true | ||||
|     }, | ||||
|     company: { // 企业名称 | ||||
|       type: String, | ||||
|       default: 'xxx ' | ||||
|     }, | ||||
|     // 是否显示下载按钮 | ||||
|     downloadButtonShow: { | ||||
|       type: Boolean, | ||||
|       default: true | ||||
|     }, | ||||
|     // 下载按钮样式 | ||||
|     downloadButtonStyle: { | ||||
|       type: Object, | ||||
|       default () { | ||||
|         return { | ||||
|           position: 'fixed', right: '50px', bottom: '30px' | ||||
|         } | ||||
|       } | ||||
|     }, | ||||
|     // 下载按钮标题 | ||||
|     downloadButtonTitle: { | ||||
|       type: String, | ||||
|       default: '下载报告' | ||||
|     }, | ||||
|     // 是否显示预览按钮 | ||||
|     previewButtonShow: { | ||||
|       type: Boolean, | ||||
|       default: true | ||||
|     }, | ||||
|     // 预览按钮样式 | ||||
|     previewButtonStyle: { | ||||
|       type: Object, | ||||
|       default () { | ||||
|         return { | ||||
|           position: 'fixed', right: '50px', bottom: '70px' | ||||
|         } | ||||
|       } | ||||
|     }, | ||||
|     // 预览按钮标题 | ||||
|     previewButtonTitle: { | ||||
|       type: String, | ||||
|       default: '预览报告' | ||||
|     } | ||||
|   }, | ||||
|   data () { | ||||
|     return { | ||||
|       preview: false, | ||||
|       downloadLoading: false, | ||||
|       previewLoading: false | ||||
|     } | ||||
|   }, | ||||
|   created () { | ||||
|   }, | ||||
|   mounted () { | ||||
|   }, | ||||
|   methods: { | ||||
|     async beforeDownload ({ html2pdf, options, pdfContent }) { | ||||
|       if (this.preview) return | ||||
|       await html2pdf() | ||||
|         .set(options) | ||||
|         .from(pdfContent) | ||||
|         .toPdf() | ||||
|         .get('pdf') | ||||
|         .then((pdf) => { | ||||
|           const totalPages = pdf.internal.getNumberOfPages() | ||||
|           for (let i = 1; i <= totalPages; i++) { | ||||
|             pdf.setPage(i) | ||||
|             pdf.addFileToVFS('MyFont.ttf', SongtiSCBlack) | ||||
|             pdf.addFont('MyFont.ttf', 'MyFont', 'normal') | ||||
|             pdf.setFont('MyFont') | ||||
|             pdf.setFontSize(10) | ||||
|             pdf.setTextColor(150) | ||||
|             pdf.text( | ||||
|               '第 ' + i + '页  共 ' + totalPages + '页', | ||||
|               pdf.internal.pageSize.getWidth() * 0.45, | ||||
|               pdf.internal.pageSize.getHeight() - 2 | ||||
|             ) | ||||
|             pdf.text( | ||||
|               this.company, | ||||
|               pdf.internal.pageSize.getWidth() * 0.79, | ||||
|               pdf.internal.pageSize.getHeight() - 2 | ||||
|             ) | ||||
|           } | ||||
|         }) | ||||
|         .save(this.filename) | ||||
|     }, | ||||
|     generateReport () { | ||||
|       this.preview = false | ||||
|       this.downloadLoading = true | ||||
|       this.$nextTick(() => { | ||||
|         this.$refs.html2Pdf.generatePdf() | ||||
|         const _this = this | ||||
|         setTimeout(function () { | ||||
|           _this.downloadLoading = false | ||||
|         }, 4000) | ||||
|       }) | ||||
|     }, | ||||
|     previewPdf () { | ||||
|       this.preview = true | ||||
|       this.previewLoading = true | ||||
|       this.$nextTick(() => { | ||||
|         this.$refs.html2Pdf.generatePdf() | ||||
|         const _this = this | ||||
|         setTimeout(function () { | ||||
|           _this.previewLoading = false | ||||
|         }, 4000) | ||||
|       }) | ||||
|     } | ||||
|   } | ||||
| 
 | ||||
| } | ||||
| </script> | ||||
| 
 | ||||
| <style scoped> | ||||
| 
 | ||||
| </style> | ||||
|  | @ -1,7 +1,7 @@ | |||
| import Vue from 'vue' | ||||
| 
 | ||||
| import d2Container from './d2-container' | ||||
| 
 | ||||
| import tableProgress from './table-progress/lib/table-progress.vue' | ||||
| // 注意 有些组件使用异步加载会有影响 | ||||
| Vue.component('d2-container', d2Container) | ||||
| Vue.component('d2-icon', () => import('./d2-icon')) | ||||
|  | @ -11,3 +11,5 @@ Vue.component('foreignKey', () => import('./foreign-key/index.vue')) | |||
| Vue.component('manyToMany', () => import('./many-to-many/index.vue')) | ||||
| Vue.component('d2p-tree-selector', () => import('./tree-selector/lib/tree-selector.vue')) | ||||
| Vue.component('dept-format', () => import('./dept-format/lib/dept-format.vue')) | ||||
| Vue.component('dvaHtml2pdf', () => import('./dvaHtml2pdf/index.vue')) | ||||
| Vue.component('table-progress', tableProgress) | ||||
|  |  | |||
|  | @ -0,0 +1,20 @@ | |||
| /* | ||||
|  * @创建文件时间: 2021-08-02 23:55:30 | ||||
|  * @Auther: 猿小天 | ||||
|  * @最后修改人: 猿小天 | ||||
|  * @最后修改时间: 2021-08-08 12:27:45 | ||||
|  * 联系Qq:1638245306 | ||||
|  * @文件介绍: | ||||
|  */ | ||||
| export default { | ||||
|   // 字段类型配置,注册之后即可在crud.js中使用了 | ||||
|   'selector-table': { | ||||
|     // 表单组件配置 | ||||
|     form: { component: { name: 'selector-table-input', props: { color: 'danger' } } }, | ||||
|     // 行组件配置 | ||||
|     component: { name: 'values-format', props: {} }, | ||||
|     // 行展示时居中 | ||||
|     align: 'center' | ||||
|     // 您还可以写更多默认配置 | ||||
|   } | ||||
| } | ||||
|  | @ -0,0 +1,14 @@ | |||
| import { d2CrudPlus } from 'd2-crud-plus' | ||||
| import group from './group' | ||||
| 
 | ||||
| function install (Vue, options) { | ||||
|   Vue.component('selector-table-input', () => import('./selector-table')) | ||||
|   if (d2CrudPlus != null) { | ||||
|     // 注册字段类型`demo-extend` | ||||
|     d2CrudPlus.util.columnResolve.addTypes(group) | ||||
|   } | ||||
| } | ||||
| // 导出install | ||||
| export default { | ||||
|   install | ||||
| } | ||||
|  | @ -0,0 +1,397 @@ | |||
| <template> | ||||
|   <div ref="selectedTableRef"> | ||||
|     <el-popover | ||||
|       placement="bottom" | ||||
|       width="400" | ||||
|       trigger="click" | ||||
|       @show="visibleChange"> | ||||
|       <div class="option"> | ||||
|         <el-input style="margin-bottom: 10px" v-model="search" clearable placeholder="请输入关键词" @change="getDict" | ||||
|                   @clear="getDict"> | ||||
|           <el-button style="width: 100px" slot="append" icon="el-icon-search"></el-button> | ||||
|         </el-input> | ||||
|         <el-table | ||||
|           ref="tableRef" | ||||
|           :data="tableData" | ||||
|           size="mini" | ||||
|           border | ||||
|           :row-key="dict.value" | ||||
|           style="width: 400px" | ||||
|           max-height="200" | ||||
|           height="200" | ||||
|           :highlight-current-row="!_elProps.tableConfig.multiple" | ||||
|           @selection-change="handleSelectionChange" | ||||
|           @row-click="handleCurrentChange" | ||||
|         > | ||||
|           <el-table-column v-if="_elProps.tableConfig.multiple" fixed type="selection" reserve-selection width="55"/> | ||||
|           <el-table-column fixed type="index" label="#" width="50"/> | ||||
|           <el-table-column :prop="item.prop" :label="item.label" :width="item.width" | ||||
|                            v-for="(item,index) in _elProps.tableConfig.columns" :key="index"/> | ||||
|         </el-table> | ||||
|         <el-pagination style="margin-top: 10px;max-width: 200px" background | ||||
|                        small | ||||
|                        :current-page="pageConfig.page" | ||||
|                        :page-size="pageConfig.limit" | ||||
|                        layout="prev, pager, next" | ||||
|                        :total="pageConfig.total" | ||||
|                        @current-change="handlePageChange" | ||||
|         /> | ||||
|       </div> | ||||
|       <div slot="reference" ref="divRef" :style="{'pointerEvents': disabled?'none':''}"> | ||||
|         <div v-if="currentValue" class="div-input el-input__inner" :class="disabled?'div-disabled':''"> | ||||
|           <div> | ||||
|             <el-tag | ||||
|               style="margin-right: 5px" | ||||
|               v-for="(item,index) in currentValue" | ||||
|               :key="index" | ||||
|               :closable="disabled" | ||||
|               size="small" | ||||
|               :hit="false" | ||||
|               type="info" | ||||
|               @close="itemClosed(item,index)" | ||||
|               disable-transitions | ||||
|             > | ||||
|               <span>{{ item[dict.label] }}</span> | ||||
|             </el-tag> | ||||
|           </div> | ||||
|         </div> | ||||
|         <el-input v-else placeholder="请选择" slot:reference  :disabled="disabled"></el-input> | ||||
|       </div> | ||||
|     </el-popover> | ||||
|   </div> | ||||
| </template> | ||||
| 
 | ||||
| <script> | ||||
| import { request } from '@/api/service' | ||||
| import XEUtils from 'xe-utils' | ||||
| import { d2CrudPlus } from 'd2-crud-plus' | ||||
| 
 | ||||
| export default { | ||||
|   name: 'selector-table-input', | ||||
|   model: { | ||||
|     prop: 'value', | ||||
|     event: ['change', 'input'] | ||||
|   }, | ||||
|   mixins: [d2CrudPlus.input, d2CrudPlus.inputDict], | ||||
|   props: { | ||||
|     // 值 | ||||
|     value: { | ||||
|       type: [String, Number, Array], | ||||
|       required: false, | ||||
|       default: '' | ||||
|     }, | ||||
|     // 数据字典配置 | ||||
|     dict: { | ||||
|       type: Object, | ||||
|       require: false | ||||
|     }, | ||||
|     // 其他配置 | ||||
|     elProps: { | ||||
|       type: Object, | ||||
|       require: false, | ||||
|       default () { | ||||
|         return { | ||||
|           tableConfig: { | ||||
|             multiple: false, | ||||
|             columns: [] | ||||
|           } | ||||
|         } | ||||
|       } | ||||
|     }, | ||||
|     // 你可以定义一些参数,通过component.props传进来 | ||||
|     color: { | ||||
|       required: false | ||||
|     }, | ||||
|     styleName: { | ||||
|       type: [Object, String], | ||||
|       required: false, | ||||
|       default () { | ||||
|         return {} | ||||
|       } | ||||
|     }, | ||||
|     disabled: { | ||||
|       type: Boolean, | ||||
|       default: false | ||||
|     } | ||||
|   }, | ||||
|   data () { | ||||
|     return { | ||||
|       // 由于value值是props参数,是不允许修改的,需要用别的值存起来 | ||||
|       currentValue: [], | ||||
|       pageConfig: { | ||||
|         page: 1, | ||||
|         limit: 5, | ||||
|         total: 0 | ||||
|       }, | ||||
|       search: null, | ||||
|       tableData: [], | ||||
|       multipleSelection: [], | ||||
|       collapseTags: false | ||||
|     } | ||||
|   }, | ||||
|   computed: { | ||||
|     // 你也可以通过computed来监听value的变化,跟watch作用类似,根据实际情况选用 | ||||
|     _elProps () { | ||||
|       return this.elProps | ||||
|     } | ||||
|   }, | ||||
|   watch: { | ||||
|     value: { | ||||
|       handler (value, oldVal) { | ||||
|         // 父组件收到input事件后会通过v-model改变value参数的值 | ||||
|         // 然后此处会watch到value的改变,发出change事件 | ||||
|         // change事件放在此处发射的好处是,当外部修改value值时,也能够触发form-data-change事件 | ||||
|         this.$emit('change', value) | ||||
|         this.$emit('input', value) | ||||
|         // 如果值是被外部改变的,则修改本组件的currentValue | ||||
|         if (Array.isArray(value) && value.length === 0) { | ||||
|           this.currentValue = null | ||||
|           this.multipleSelection = null | ||||
|         } else { | ||||
|           if (value && this.dispatch) { | ||||
|             this.dispatch('ElFormItem', 'el.form.blur') | ||||
|           } | ||||
|         } | ||||
|       }, | ||||
|       deep: true, | ||||
|       immediate: true | ||||
|     }, | ||||
|     multipleSelection: { | ||||
|       handler (newValue, oldVal) { | ||||
|         const { tableConfig } = this._elProps | ||||
|         // 是否多选 | ||||
|         if (!tableConfig.multiple) { | ||||
|           this.currentValue = [newValue] | ||||
|         } else { | ||||
|           this.currentValue = newValue | ||||
|         } | ||||
|       }, | ||||
|       deep: true, | ||||
|       immediate: true | ||||
|     } | ||||
|     // currentValue (newValue, oldVal) { | ||||
|     //   const { tableConfig } = this._elProps | ||||
|     //   const { value } = this.dict | ||||
|     //   if (newValue) { | ||||
|     //     if (!tableConfig.multiple) { | ||||
|     //       if (newValue[0]) { | ||||
|     //         this.$emit('input', newValue[0][value]) | ||||
|     //         this.$emit('change', newValue[0][value]) | ||||
|     //       } | ||||
|     //     } else { | ||||
|     //       console.log(newValue) | ||||
|     //       const result = newValue.map((item) => { | ||||
|     //         return item[value] | ||||
|     //       }) | ||||
|     //       this.$emit('input', result) | ||||
|     //       this.$emit('change', result) | ||||
|     //     } | ||||
|     //   } | ||||
|     // } | ||||
|   }, | ||||
|   mounted () { | ||||
|     // 给currentValue设置初始值 | ||||
|     this.setCurrentValue(this.value) | ||||
|   }, | ||||
|   methods: { | ||||
|     // 设置显示值 | ||||
|     setCurrentValue (val) { | ||||
|       if (val.toString().length > 0) { | ||||
|         // 在这里对 传入的value值做处理 | ||||
|         const { url, value, label } = this.dict | ||||
|         const params = {} | ||||
|         params[value] = val | ||||
|         return request({ | ||||
|           url: url, | ||||
|           params: params, | ||||
|           method: 'get' | ||||
|         }).then(res => { | ||||
|           const { data } = res.data | ||||
|           if (data && data.length > 0) { | ||||
|             this.currentValue = data | ||||
|           } else { | ||||
|             this.currentValue = null | ||||
|           } | ||||
|         }) | ||||
|       } else { | ||||
|         this.currentValue = null | ||||
|       } | ||||
|     }, | ||||
|     // 获取数据 | ||||
|     getDict () { | ||||
|       const that = this | ||||
|       let url | ||||
|       if (typeof that.dict.url === 'function') { | ||||
|         const form = that.d2CrudContext.getForm() | ||||
|         url = that.dict.url(that.dict, { form }) | ||||
|       } else { | ||||
|         url = that.dict.url | ||||
|       } | ||||
|       let dictParams = {} | ||||
|       if (that.dict.params) { | ||||
|         dictParams = { ...that.dict.params } | ||||
|       } | ||||
|       const params = { | ||||
|         page: that.pageConfig.page, | ||||
|         limit: that.pageConfig.limit | ||||
|       } | ||||
|       if (that.search) { | ||||
|         params.search = that.search | ||||
|         params.page = 1 | ||||
|       } | ||||
|       if (that._elProps.tableConfig.data === undefined || that._elProps.tableConfig.data.length === 0) { | ||||
|         request({ | ||||
|           url: url, | ||||
|           method: 'get', | ||||
|           params: { ...params, ...dictParams } | ||||
|         }).then(res => { | ||||
|           const { data, page, limit, total } = res.data | ||||
|           that.pageConfig.page = page | ||||
|           that.pageConfig.limit = limit | ||||
|           that.pageConfig.total = total | ||||
|           if (that._elProps.tableConfig.isTree) { | ||||
|             that.tableData = XEUtils.toArrayTree(data, { parentKey: 'parent', key: 'id', children: 'children' }) | ||||
|           } else { | ||||
|             that.tableData = data | ||||
|           } | ||||
|         }) | ||||
|       } else { | ||||
|         that.tableData = that._elProps.tableConfig.data | ||||
|       } | ||||
|     }, | ||||
|     /** | ||||
|      * 下拉框展开/关闭 | ||||
|      * @param bool | ||||
|      */ | ||||
|     visibleChange () { | ||||
|       const that = this | ||||
|       that.getDict() | ||||
|       const { tableConfig } = that._elProps | ||||
|       if (tableConfig.multiple) { | ||||
|         that.$refs.tableRef.clearSelection() // 先清空选择,再赋值选择 | ||||
|         that.currentValue ? that.currentValue.forEach(item => { | ||||
|           that.$refs.tableRef.toggleRowSelection(item, true) | ||||
|         }) : null | ||||
|       } | ||||
|     }, | ||||
|     /** | ||||
|      * 分页 | ||||
|      * @param page | ||||
|      */ | ||||
|     handlePageChange (page) { | ||||
|       this.pageConfig.page = page | ||||
|       this.getDict() | ||||
|     }, | ||||
|     /** | ||||
|      * 表格多选 | ||||
|      * @param val:Array | ||||
|      */ | ||||
|     handleSelectionChange (val) { | ||||
|       this.multipleSelection = val | ||||
|       this.$emit('checkChange', val) | ||||
|       const result = val.map((item) => { | ||||
|         return item[this.dict.value] | ||||
|       }) | ||||
|       this.$emit('input', result) | ||||
|       this.$emit('change', result) | ||||
|     }, | ||||
|     /** | ||||
|      * 表格单选 | ||||
|      * @param val:Object | ||||
|      */ | ||||
|     handleCurrentChange (val) { | ||||
|       const { tableConfig } = this._elProps | ||||
|       if (!tableConfig.multiple) { | ||||
|         this.multipleSelection = val | ||||
|         this.$emit('radioChange', val) | ||||
|         this.$emit('input', val[this.dict.value]) | ||||
|         this.$emit('change', val[this.dict.value]) | ||||
|       } | ||||
|     }, | ||||
|     /*** | ||||
|      * 清空 | ||||
|      */ | ||||
|     onClear () { | ||||
|       const { tableConfig } = this._elProps | ||||
|       if (!tableConfig.multiple) { | ||||
|         this.$emit('input', '') | ||||
|         this.$emit('change', '') | ||||
|       } else { | ||||
|         this.$emit('input', []) | ||||
|         this.$emit('change', []) | ||||
|       } | ||||
|     }, | ||||
|     /** | ||||
|      * tag删除事件 | ||||
|      * @param obj | ||||
|      */ | ||||
|     itemClosed (obj, index) { | ||||
|       const { tableConfig } = this._elProps | ||||
|       XEUtils.remove(this.multipleSelection, index) | ||||
|       XEUtils.remove(this.currentValue, index) | ||||
|       if (!tableConfig.multiple) { | ||||
|         this.$emit('input', '') | ||||
|         this.$emit('change', '') | ||||
|       } else { | ||||
|         this.$refs.tableRef?.toggleRowSelection(obj, false) | ||||
|         // const { value } = this.dict | ||||
|         // const result = this.currentValue.map((item) => { | ||||
|         //   return item[value] | ||||
|         // }) | ||||
|         // this.$emit('input', result) | ||||
|         // this.$emit('change', result) | ||||
|       } | ||||
|     } | ||||
|   } | ||||
| } | ||||
| </script> | ||||
| <style scoped> | ||||
| .option { | ||||
|   height: auto; | ||||
|   line-height: 1; | ||||
|   padding: 5px; | ||||
|   background-color: #fff; | ||||
| } | ||||
| 
 | ||||
| </style> | ||||
| <style lang="scss"> | ||||
| .popperClass { | ||||
|   height: 320px; | ||||
| } | ||||
| 
 | ||||
| .el-select-dropdown__wrap { | ||||
|   max-height: 310px !important; | ||||
| } | ||||
| 
 | ||||
| .tableSelector { | ||||
|   .el-icon, .el-tag__close { | ||||
|     display: none; | ||||
|   } | ||||
| } | ||||
| 
 | ||||
| .div-input { | ||||
|   -webkit-appearance: none; | ||||
|   background-color: #FFF; | ||||
|   background-image: none; | ||||
|   border-radius: 4px; | ||||
|   border: 1px solid #DCDFE6; | ||||
|   -webkit-box-sizing: border-box; | ||||
|   box-sizing: border-box; | ||||
|   color: #606266; | ||||
|   display: inline-block; | ||||
|   min-height: 40px; | ||||
|   line-height: 40px; | ||||
|   outline: 0; | ||||
|   padding: 0 15px; | ||||
|   -webkit-transition: border-color .2s cubic-bezier(.645, .045, .355, 1); | ||||
|   transition: border-color .2s cubic-bezier(.645, .045, .355, 1); | ||||
|   min-width: 120px; | ||||
| } | ||||
| .div-disabled{ | ||||
|   background-color: #F5F7FA; | ||||
|   border-color: #E4E7ED; | ||||
|   color: #C0C4CC; | ||||
|   cursor: not-allowed; | ||||
|   pointer-events: none; | ||||
| } | ||||
| </style> | ||||
|  | @ -0,0 +1,12 @@ | |||
| export default { | ||||
|   // 字段类型配置,注册之后即可在crud.js中使用了 | ||||
|   'table-progress': { | ||||
|     // 表单组件配置 | ||||
|     form: { component: { name: 'form-input', props: { color: 'danger' } } }, | ||||
|     // 行组件配置 | ||||
|     component: { name: 'table-progress', props: {} }, | ||||
|     // 行展示时居中 | ||||
|     align: 'center' | ||||
|     // 您还可以写更多默认配置 | ||||
|   } | ||||
| } | ||||
|  | @ -0,0 +1,13 @@ | |||
| import { d2CrudPlus } from 'd2-crud-plus' | ||||
| import group from './group' | ||||
| function install (Vue) { | ||||
|   Vue.component('table-progress', () => import('./lib/table-progress')) | ||||
|   if (d2CrudPlus != null) { | ||||
|     // 注册字段类型`demo-extend` | ||||
|     d2CrudPlus.util.columnResolve.addTypes(group) | ||||
|   } | ||||
| } | ||||
| 
 | ||||
| export default { | ||||
|   install | ||||
| } | ||||
|  | @ -0,0 +1,55 @@ | |||
| <template> | ||||
|   <div> | ||||
|     <el-progress :percentage="currentValue" :color="setColor" :format="format"></el-progress> | ||||
|   </div> | ||||
| </template> | ||||
| <script> | ||||
| // 行展示组件进阶版 | ||||
| // 本示例演示要对传入的值做一些改变,然后再展示 | ||||
| export default { | ||||
|   name: 'table-progress', | ||||
|   props: { | ||||
|     // 接收row.xxx的值 | ||||
|     value: { | ||||
|       type: String || Number, | ||||
|       required: false | ||||
|     } | ||||
|   }, | ||||
|   data () { | ||||
|     return { | ||||
|       currentValue: '' | ||||
|     } | ||||
|   }, | ||||
|   watch: { | ||||
|     value (value) { | ||||
|       // this.$emit('change', value) | ||||
|       if (this.currentValue === value) { | ||||
|         return | ||||
|       } | ||||
|       this.setValue(value) | ||||
|     } | ||||
|   }, | ||||
|   created () { | ||||
|     this.setValue(this.value) | ||||
|   }, | ||||
|   methods: { | ||||
|     setValue (value) { | ||||
|       // 在这里对 传入的value值做处理 | ||||
|       this.currentValue = Number(this.value) | ||||
|       // 根据值的key 递归获取对应的名称 | ||||
|     }, | ||||
|     setColor () { | ||||
|       if (this.value <= 50) { | ||||
|         return '#F56C6C' | ||||
|       } else if (this.value > 50 && this.value < 80) { | ||||
|         return '#E6A23C' | ||||
|       } else { | ||||
|         return '#67C23A' | ||||
|       } | ||||
|     }, | ||||
|     format (percentage) { | ||||
|       return `${percentage}%` | ||||
|     } | ||||
|   } | ||||
| } | ||||
| </script> | ||||
|  | @ -104,7 +104,7 @@ export default { | |||
|         }, | ||||
|         grid: { | ||||
|           top: 40, | ||||
|           left: 40, | ||||
|           left: 50, | ||||
|           right: 65, | ||||
|           bottom: 75 | ||||
|         }, | ||||
|  |  | |||
|  | @ -95,7 +95,7 @@ export default { | |||
|         }, | ||||
|         grid: { | ||||
|           top: 40, | ||||
|           left: 40, | ||||
|           left: 50, | ||||
|           right: 65, | ||||
|           bottom: 60 | ||||
|         }, | ||||
|  |  | |||
|  | @ -98,7 +98,7 @@ export default { | |||
|         }, | ||||
|         grid: { | ||||
|           top: 40, | ||||
|           left: 40, | ||||
|           left: 50, | ||||
|           right: 65, | ||||
|           bottom: 60 | ||||
|         }, | ||||
|  |  | |||
		Loading…
	
		Reference in New Issue
	
	 猿小天
						猿小天