index.vue 11 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350
  1. <template>
  2. <FormDialog
  3. :width="width"
  4. class="parameter_setting_form_dialog"
  5. v-if="formVisible"
  6. :defaultFormData="{}"
  7. :visible="formVisible"
  8. :title="formTitle"
  9. :submitLoading="formSubmitLoading"
  10. @close="HandleFormClose"
  11. @confirm="HandleFormConfirm"
  12. >
  13. <template #form_pre>
  14. <div class="dictionary_box">
  15. <Table
  16. v-model:tableRef="configTableDom"
  17. :tableColumns="finalTableColumns"
  18. :tableData="tableData"
  19. :hidePagination="true">
  20. <template #moveable="{row,currentIndex}">
  21. <slot></slot>
  22. <TableRowDragUpDown
  23. :startIndex="startDragIndex()"
  24. :endIndex="endDragIndex(tableData)"
  25. v-if="(currentIndex - 1) >= startDragIndex() && (currentIndex - 1) <= endDragIndex(tableData)"
  26. :currentIndex="currentIndex"
  27. :tableRow="row" :defaultTableData="tableData"
  28. @moveChange="HandleRowMove"/>
  29. </template>
  30. <template #num="{row,currentIndex}">
  31. {{ currentIndex }}
  32. </template>
  33. <template v-slot:[middleColumnItm?.name]="{row}">
  34. <slot :name="[middleColumnItm?.name]" :row="row">
  35. </slot>
  36. </template>
  37. <template #operation="{row,currentIndex}">
  38. <div class="table_row_option">
  39. <!-- row.defaultStatus ? -->
  40. <span :class="disabledEditRowScene ?
  41. (disabledEditRowScene(row,currentIndex,tableData) ? 'editor_disable' : 'el_button_editor') :
  42. 'el_button_editor'"
  43. @click="disabledEditRowScene ?
  44. (disabledEditRowScene(row,currentIndex,tableData) ? '' : HandleConfigEditOrSave(row)) :
  45. HandleConfigEditOrSave(row)"
  46. >{{row.tmpId ? '保存' : '编辑'}}</span>
  47. <span v-if="row.tmpId" class="el_button_editor" @click="HandleConfigCancel(row)">取消</span>
  48. <!-- row.defaultStatus -->
  49. <span v-else
  50. :class="disabledDeleteRowScene ?
  51. (disabledDeleteRowScene(row,currentIndex,tableData) ? 'editor_disable' : 'el_button_delete') :
  52. 'el_button_delete'"
  53. @click="disabledDeleteRowScene ?
  54. (disabledDeleteRowScene(row,currentIndex,tableData) ? '' : HandleConfigDelete(row)) :
  55. HandleConfigDelete(row)"
  56. >删除</span>
  57. </div>
  58. </template>
  59. </Table>
  60. <div class="add_option" @click="HandleAddConfig">
  61. <el-icon><CloseBold /></el-icon>
  62. <span>增加选项配置</span>
  63. </div>
  64. </div>
  65. </template>
  66. </FormDialog>
  67. <!-- 删除弹窗 -->
  68. <Dialog
  69. v-if="dialogVisible"
  70. :submitLoading="dialogSubmitLoading"
  71. :visible="dialogVisible"
  72. @confirm="HandleDialogConfirm"
  73. @close="HandleDialogClose">
  74. 是否确认删除?
  75. </Dialog>
  76. </template>
  77. <script setup lang="ts">
  78. import { ref,watch, nextTick } from 'vue';
  79. import {ElMessage} from 'element-plus'
  80. import FormDialog from '@/baseComponents/FormDialog.vue';
  81. import Dialog from '@/baseComponents/Dialog.vue';
  82. import TableRowDragUpDown from '@/baseComponents/TableRowDragUpDown.vue';
  83. import Table from '../Table.vue';
  84. import {tableColumns} from './table'
  85. interface MiddleColumnItm {
  86. name:string,
  87. label:string
  88. }
  89. const props = defineProps({
  90. startDragIndex:{
  91. type:Function,
  92. required:true
  93. },
  94. endDragIndex:{
  95. type:Function,
  96. required:true
  97. },
  98. width:{ //弹窗宽度
  99. type:String,
  100. },
  101. formTitle:{ //弹窗标题
  102. type:String,
  103. },
  104. middleColumnItm:{ //表列中间的动态列
  105. type:Object as ()=>MiddleColumnItm
  106. },
  107. defaultTableData:{
  108. type:Array,
  109. default:()=>[]
  110. },
  111. disabledDeleteRowScene:{ // 禁止删除行 的条件: true 禁止 false 允许
  112. type:Function
  113. },
  114. disabledEditRowScene:{ // 禁止编辑行 的条件 :true 禁止 false 允许
  115. type:Function
  116. },
  117. })
  118. const emit = defineEmits(['editConfirm','addConfirm','deleteConfirm','entiretyConfirm'])
  119. /**
  120. * 1. 参数配置: 表单弹窗信息
  121. */
  122. const formVisible = defineModel('formVisible') //
  123. const deleteFlag = defineModel('deleteFlag') // 当下 删除弹窗确认 是否成功的标识 // success | fail | none
  124. const formDialogConfirmFlag = defineModel('formDialogConfirmFlag')
  125. const formSubmitLoading = ref(false)
  126. const finalTableColumns = ref([...tableColumns.value]) //最终渲染的表头
  127. const tableData = ref<any[]>([]) //表数据
  128. const configTableDom = ref()
  129. // 处理表行的上下移动
  130. const HandleRowMove = (val)=>{
  131. tableData.value = val
  132. }
  133. // 处理参数配置的增删改查
  134. // 配置项添加
  135. const HandleAddConfig = async ()=>{
  136. if(props.middleColumnItm?.label === '跟进状态'){
  137. tableData.value.splice(tableData.value.length - 3,0,{
  138. // 临时id _ 待完善
  139. id:`tmp_${new Date().getTime()}_${tableData.value.length + 1}`,
  140. tmpId:(Number(tableData.value[tableData.value.length - 1]?.tmpId) || 0) + 1, //新增时候的临时id
  141. [props.middleColumnItm?.name]:'',
  142. defaultStatus:1, // defaultStatus: 0默认项 1非默认项 ,后续可能会用
  143. })
  144. }else{
  145. tableData.value.push({
  146. // 临时id _ 待完善
  147. id:`tmp_${new Date().getTime()}_${tableData.value.length + 1}`,
  148. tmpId:(Number(tableData.value[tableData.value.length - 1]?.tmpId) || 0) + 1, //新增时候的临时id
  149. [props.middleColumnItm?.name]:'',
  150. defaultStatus:1, // defaultStatus: 0默认项 1非默认项 ,后续可能会用
  151. })
  152. }
  153. await nextTick()
  154. // 新增元素后滚动到表格最底层
  155. configTableDom.value.setScrollTop(configTableDom.value.layout.table.refs.bodyWrapper.firstElementChild.firstElementChild.scrollHeight)
  156. }
  157. // 配置项保存 /编辑
  158. const HandleConfigEditOrSave = async (row)=>{
  159. // 初次新增确认 或者 准备变成编辑状态
  160. if(!row.editFlag){
  161. if(row.tmpId){
  162. // 初次新增确认 调用新增接口
  163. if(!(row?.[props?.middleColumnItm?.name]) ){
  164. ElMessage.warning('请填写内容')
  165. return
  166. }
  167. let params = {
  168. [props.middleColumnItm.name]:row?.[props?.middleColumnItm?.name],
  169. }
  170. // 调用新增接口
  171. emit('addConfirm',row,params)
  172. }else{
  173. // 准备变成编辑状态
  174. row.editFlag = 'edit'
  175. row.tmpId = row.id
  176. }
  177. }else{
  178. // 准备保存修改 调用修改接口
  179. if(!row?.[props?.middleColumnItm?.name]){
  180. ElMessage.warning('请填写类别内容')
  181. return
  182. }
  183. let params = {
  184. id:row.id,
  185. [props.middleColumnItm.name]:row?.[props?.middleColumnItm?.name],
  186. }
  187. emit('editConfirm',row,params)
  188. }
  189. }
  190. // 取消配置项操作
  191. const HandleConfigCancel = (row)=>{
  192. if(!row.editFlag){
  193. // 不是已有的数据,要删除
  194. tableData.value = tableData.value.filter(item=>{
  195. return item.id !== row.id
  196. })
  197. }else{
  198. row.tmpId = ''
  199. row.editFlag = ''
  200. }
  201. }
  202. // 配置项删除
  203. const HandleConfigDelete = async (row)=>{
  204. dialogVisible.value = true
  205. currentEditRow.value = row
  206. }
  207. const HandleFormConfirm = ()=>{
  208. formSubmitLoading.value = true
  209. // 整体表单提交
  210. emit('entiretyConfirm',tableData.value)
  211. }
  212. const HandleFormClose = ()=>{
  213. formVisible.value = false
  214. formSubmitLoading.value = false
  215. }
  216. watch(()=>deleteFlag.value,(newVal)=>{
  217. if(newVal == 'success'){
  218. HandleDialogClose()
  219. dialogSubmitLoading.value = false
  220. deleteFlag.value = 'none'
  221. }else if(newVal == 'fail'){
  222. dialogSubmitLoading.value = false
  223. deleteFlag.value = 'none'
  224. }
  225. })
  226. watch(()=>formDialogConfirmFlag.value,(newVal)=>{
  227. if(newVal == 'success'){
  228. HandleFormClose()
  229. formDialogConfirmFlag.value = 'none'
  230. }else if(newVal == 'fail'){
  231. formSubmitLoading.value = false
  232. formDialogConfirmFlag.value = 'none'
  233. }
  234. })
  235. /**
  236. * 2. 参数配置: 删除弹窗 信息
  237. */
  238. const dialogVisible = ref(false)
  239. const dialogSubmitLoading = ref(false)
  240. const currentEditRow = ref()
  241. const HandleDialogClose = ()=>{
  242. dialogVisible.value = false
  243. currentEditRow.value = null
  244. }
  245. const HandleDialogConfirm = async ()=>{
  246. dialogSubmitLoading.value = true
  247. let row = currentEditRow.value
  248. emit('deleteConfirm',row)
  249. }
  250. // 动态变更最终表列
  251. watch(()=>props.middleColumnItm,(newVal)=>{
  252. if(newVal){
  253. finalTableColumns.value = tableColumns.value.map((item,index)=>{
  254. if(index == 2){
  255. return [
  256. {
  257. name:props.middleColumnItm?.name,
  258. label:props.middleColumnItm?.label,
  259. width:'350',
  260. fixed:'',
  261. align:'left',
  262. minWdth:'',
  263. custom:true,
  264. },
  265. item
  266. ]
  267. }
  268. return item
  269. }).flat()
  270. }
  271. },{immediate:true,deep:true})
  272. // 动态变更表数据
  273. watch(()=>props.defaultTableData,(val)=>{
  274. tableData.value = JSON.parse(JSON.stringify(val)) || []
  275. },{immediate:true,deep:true})
  276. </script>
  277. <style lang="scss" scoped>
  278. .dictionary_box{
  279. width:100%;
  280. height: 480px;
  281. overflow: auto;
  282. display: flex;
  283. flex-direction: column;
  284. gap:10px;
  285. :deep(.page_table){
  286. overflow: auto;
  287. }
  288. .add_option{
  289. flex-shrink: 0;
  290. display: flex;
  291. justify-content: center;
  292. align-items: center;
  293. gap:8px;
  294. background-color: rgba(46, 100, 250,0.1);
  295. color:#2E64FA;
  296. padding:4px auto;
  297. text-align: center;
  298. border-radius: 6px;
  299. cursor: pointer;
  300. :deep(.el-icon){
  301. transform: rotate(45deg);
  302. }
  303. }
  304. }
  305. .parameter_setting_form_dialog{
  306. :deep(.el-dialog__body){
  307. min-height: 500px !important;
  308. max-height: 500px !important;
  309. padding:20px !important
  310. }
  311. }
  312. </style>