index.vue 16 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535
  1. <template>
  2. <div class="end_item container">
  3. <div class="container_left end_item">
  4. <FormSearchGroup :searchList="accountFormSearhList" @searchChange="HandleSearchChange"/>
  5. <div class="page_jg_20"/>
  6. <Table
  7. :hidePagination="true"
  8. class="teacher_table"
  9. :tableColumns="userTableColumns"
  10. :tableData="userAccountData"
  11. :tableRowClassName="tableRowClassName"
  12. @rowClick="HandleSelectUser"
  13. ></Table>
  14. </div>
  15. <div class="container_right end_item">
  16. <div class="page_search">
  17. <div class="search_content">
  18. <div class="content_left">
  19. <TabSearch :tabList="provinceTablist"
  20. :defaultTabKey="defaultProvince" tabType="line"
  21. @tabChange="HandleProvinceChange" />
  22. </div>
  23. <div class="content_right">
  24. <span v-if="isConfigMode" class="config_switch_desc">
  25. {{ selectedUser?.id ? `当前选中的员工:${selectedUser.username}` : '暂无选中的员工' }}
  26. </span>
  27. <el-switch v-model="isConfigMode" style="--el-switch-on-color: #2E64FA" />
  28. <span class="config_switch_desc" :style="{color:isConfigMode ? '#2E64FA' : '#999999'}">选中员工配置关系</span>
  29. <el-button class="button_border" @click="HandleOpenGroup">分组管理</el-button>
  30. </div>
  31. </div>
  32. </div>
  33. <div class="page_jg_20" />
  34. <Table :hidePagination="true"
  35. :tableColumns="filterGroupTableColumns"
  36. :tableData="groupPeopleTableData">
  37. <template #city="{row}">
  38. {{ row?.city?.cityName }}
  39. </template>
  40. <template v-for="column in filterGroupTableColumns.slice(1)" :key="column.name" v-slot:[column.name]="{row}">
  41. <div class="cell_container" @click="HandleAddUser(row, column.name)">
  42. <template v-if="row?.[column.name]?.length > 0">
  43. <el-tooltip
  44. v-for="(staff,index) in row?.[column.name]"
  45. :key="staff.id"
  46. effect="dark"
  47. :content="`${staff.userName}`"
  48. placement="top-start"
  49. >
  50. <div v-if="isConfigMode" class="teacher_tag">
  51. <span :title="staff.userName">{{ staff.userName }}</span>
  52. <el-icon class="delete_icon" @click.stop="OpenDeleteDialog(row, column,index)"><Close /></el-icon>
  53. </div>
  54. <div v-else class="disabled_teacher">
  55. <span :title="staff.userName">{{staff.userName}}</span>
  56. </div>
  57. </el-tooltip>
  58. </template>
  59. <template v-else>
  60. <span v-if="isConfigMode" class="placeholder_text" >请选择员工</span>
  61. <span v-else>-</span>
  62. </template>
  63. </div>
  64. </template>
  65. </Table>
  66. </div>
  67. </div>
  68. <!-- 分组管理弹窗 -->
  69. <FormTableEdit
  70. style="flex-grow: 0;"
  71. addOperationName="增加分组"
  72. :startDragIndex="()=>{return 0}"
  73. :endDragIndex="(params)=>{return params.length}"
  74. formTitle="分组管理"
  75. :middleColumnItm="{name:'title',label:'分组名称'}"
  76. :disabledDeleteRowScene="DisabledDeleteGroupRowScene"
  77. :disabledEditRowScene="()=>{return false}"
  78. :defaultTableData="gorupTableData"
  79. v-model:formVisible="formVisible"
  80. v-model:deleteFlag="deleteFlag"
  81. v-model:formDialogConfirmFlag="formDialogConfirmFlag"
  82. @editConfirm = 'HandleEditGroup'
  83. @addConfirm = 'HandleAddGroup'
  84. @deleteConfirm = 'HandleDeleteGroup'
  85. @tableDrag="HandlTableDrag"
  86. @entiretyConfirm = "formDialogConfirmFlag = 'success'"
  87. >
  88. <template #title="{row,currentIndex}">
  89. <el-input v-model="row.title" v-if="row.tmpId" placeholder="请输fdff入内容" />
  90. <span v-else>{{ row.title }}</span>
  91. </template>
  92. </FormTableEdit>
  93. <!-- 地区 组内用户 删除弹窗 -->
  94. <Dialog
  95. style="flex-grow: 0;"
  96. v-if="dialogVisible"
  97. :submitLoading="dialogSubmitLoading"
  98. :visible="dialogVisible"
  99. @confirm="HandleDialogConfirm"
  100. @close="HandleDialogClose">
  101. 请确认是否确认删除{{ currentDeleteColumn.label }} {{currentDeleteCell.userName}} {{provinceTablist.find(item=>item.key == defaultProvince)?.label}}{{currentDeleteRow.city.cityName}}的权限?
  102. </Dialog>
  103. </template>
  104. <script setup lang="ts">
  105. import { onMounted, ref } from 'vue';
  106. import FormSearchGroup from '@/baseComponents/FormSearchGroup.vue';
  107. import {accountFormSearhList} from './formSearch'
  108. import Table from '@/baseComponents/Table.vue';
  109. import TabSearch from '@/baseComponents/TabSearch.vue';
  110. import FormTableEdit from '@/baseComponents/formTableEdit/index.vue'
  111. import Dialog from '@/baseComponents/Dialog.vue';
  112. import {groupTableColumns,userTableColumns, } from './table'
  113. import {provinceTablist} from './tabSearch'
  114. import {
  115. getAllUserApi,
  116. getGroupListApi,
  117. addGroupListApi,
  118. deleteGroupListApi,
  119. updateGroupListApi,
  120. getGroupDataApi,
  121. addCityGroupPeopleApi,
  122. deleteCityGroupPeopleApi,
  123. sortGroupListApi,
  124. } from '@/api/groupManage'
  125. import { ElMessage } from 'element-plus';
  126. /**
  127. * 1. 左侧 员工相关信息及操作
  128. */
  129. // 员工账号信息
  130. const userAccountData = ref([])
  131. // 当前选中的用户
  132. const selectedUser = ref()
  133. const searchParams = ref({
  134. queryStr:'',
  135. })
  136. // 设置表行选中 样式
  137. const tableRowClassName = ({row,rowIndex})=>{
  138. if(row.id == selectedUser.value?.id){
  139. return 'active_row'
  140. }
  141. }
  142. // 行选中 选择员工
  143. const HandleSelectUser = (user) => {
  144. selectedUser.value = {
  145. id:user.id,
  146. username:user.username,
  147. account:user.account,
  148. };
  149. };
  150. // 获取所有的用户
  151. const GetAllUserList = async ()=>{
  152. let params = {
  153. username:searchParams.value.queryStr
  154. }
  155. let res = await getAllUserApi(params)
  156. if(res?.code == 200){
  157. userAccountData.value = res.data || []
  158. }
  159. }
  160. const HandleSearchChange = async (params,key)=>{
  161. searchParams.value = {
  162. ...searchParams.value,
  163. ...params
  164. }
  165. await GetAllUserList()
  166. }
  167. /**
  168. * 2. 右侧分组展示信息 及操作
  169. */
  170. // 分组信息
  171. const isConfigMode = ref(false)
  172. const defaultProvince = ref('')
  173. const filterGroupTableColumns = ref([...groupTableColumns.value])
  174. const groupPeopleTableData = ref([]) //分组人员表格配置
  175. /** 处理不同省份下的 城市 组别员工 配置 */
  176. const allProvinceUserConfig = ref([]) //所有省份下的用户配置信息
  177. // 获取所有省份、所有市区下的组别人员配置
  178. const GetGroupData = async ()=>{
  179. let res = await getGroupDataApi()
  180. if(res?.code == 200){
  181. allProvinceUserConfig.value = res.data
  182. provinceTablist.value = res.data.map(item=>{
  183. return {
  184. label:item.provinceName,
  185. key:item.provinceId,
  186. }
  187. })
  188. // 赋值默认的省份
  189. defaultProvince.value = provinceTablist.value[0]?.key
  190. RenderProvincePeopleConfig()
  191. }
  192. }
  193. // 处理省份切换
  194. const HandleProvinceChange = (val)=>{
  195. defaultProvince.value = val
  196. RenderProvincePeopleConfig()
  197. }
  198. // 渲染 不同省份下的 表格人员配置
  199. const RenderProvincePeopleConfig = ()=>{
  200. let defaultProvinceConfig = allProvinceUserConfig.value.find(item=>{
  201. return item.provinceId == defaultProvince.value
  202. })
  203. groupPeopleTableData.value = defaultProvinceConfig.cityData.map(item=>{
  204. return {
  205. city:{
  206. cityName:item.cityName,
  207. cityId:item.cityId
  208. },
  209. ...(item.userData)
  210. }
  211. })
  212. }
  213. /** 省市 分组 添加员工 */
  214. const HandleAddUser = async (row, cell) => {
  215. if (!isConfigMode.value) return;
  216. if (!selectedUser.value) return;
  217. let teacherMsg = {
  218. id: selectedUser.value?.id,
  219. userName: selectedUser.value?.username,
  220. account:selectedUser.value?.account
  221. }
  222. if (!row[cell]) {
  223. row[cell] = [];
  224. }
  225. let params = {
  226. groupId: cell,
  227. userId: teacherMsg.id,
  228. provinceId: defaultProvince.value,
  229. cityId: row.city.cityId,
  230. }
  231. let res = await addCityGroupPeopleApi(params)
  232. if(res?.code == 200){
  233. ElMessage.success(res?.msg)
  234. teacherMsg.id = res.data
  235. row[cell].push(teacherMsg);
  236. // 重新查询分组 _更新禁删权限
  237. await GetGroupList()
  238. }
  239. };
  240. /**
  241. * 3. 删除员工的弹窗 及操作
  242. */
  243. const dialogVisible = ref(false)
  244. const dialogSubmitLoading = ref(false)
  245. const currentDeleteCell = ref() //当前准备删除的(员工)单元格数据
  246. const currentDeleteRow = ref() //当前准备删除的(员工)所在行数据
  247. const currentDeleteColumn = ref() //当前准备删除的(员工)所在列信息
  248. // 移除员工
  249. const HandleDialogConfirm = async ()=>{
  250. dialogSubmitLoading.value = true
  251. let res = undefined
  252. try{
  253. res = await deleteCityGroupPeopleApi(currentDeleteCell.value.id)
  254. }catch{}
  255. if(res?.code == 200){
  256. ElMessage.success(res?.msg)
  257. currentDeleteRow.value[currentDeleteColumn.value.name] = currentDeleteRow.value[currentDeleteColumn.value.name].filter(item=>{
  258. return item.id !== currentDeleteCell.value.id
  259. })
  260. HandleDialogClose()
  261. // 重新查询分组 _更新禁删权限
  262. await GetGroupList()
  263. }else{
  264. dialogSubmitLoading.value = false
  265. }
  266. }
  267. const HandleDialogClose = ()=>{
  268. currentDeleteCell.value = null
  269. currentDeleteRow.value = null
  270. currentDeleteColumn.value = null
  271. dialogVisible.value = false
  272. dialogSubmitLoading.value = false
  273. }
  274. const OpenDeleteDialog = (row, cellObj,index)=>{
  275. if (!isConfigMode.value) return;
  276. dialogVisible.value = true
  277. currentDeleteCell.value = row[cellObj.name][index]
  278. currentDeleteRow.value = row
  279. currentDeleteColumn.value = cellObj
  280. }
  281. /**
  282. * 4. 分组管理 弹窗相关配置
  283. */
  284. const formVisible = ref(false)
  285. const formDialogConfirmFlag = ref('')
  286. const deleteFlag = ref('')
  287. const gorupTableData = ref([])
  288. const HandleOpenGroup = ()=>{
  289. formVisible.value = true
  290. }
  291. // 获取分组列表信息 并赋值给表头
  292. const GetGroupList = async ()=>{
  293. let res = await getGroupListApi()
  294. if(res?.code == 200){
  295. gorupTableData.value = res.data
  296. let extraTableColumns = res.data.map(item=>{
  297. return {
  298. name: item.id,
  299. label: item.title,
  300. width: '120',
  301. fixed: '',
  302. align: 'center',
  303. minWidth: '',
  304. custom: true,
  305. }
  306. })
  307. // 给默认展示的表格的组头信息赋值
  308. filterGroupTableColumns.value = [
  309. ...groupTableColumns.value,
  310. ...extraTableColumns
  311. ]
  312. }
  313. }
  314. // 修改分组
  315. const HandleEditGroup = async (row,params,sortCode)=>{
  316. let transferParams = {
  317. id: row.id,
  318. title: params.title,
  319. sortCode
  320. }
  321. let res = await updateGroupListApi(transferParams)
  322. if(res?.code == 200){
  323. ElMessage.success(res?.msg)
  324. row.editFlag = ''
  325. row.tmpId = ''
  326. console.log('当前行',row)
  327. // 重新查询
  328. await GetGroupList()
  329. }
  330. }
  331. // 添加分组
  332. const HandleAddGroup = async (row,params,sortCode)=>{
  333. let transferParams = {
  334. title: params.title,
  335. sortCode
  336. }
  337. let res = await addGroupListApi(transferParams)
  338. if(res?.code == 200){
  339. ElMessage.success(res?.msg)
  340. row.tmpId = ''
  341. await GetGroupList()
  342. }
  343. }
  344. // 删除分组
  345. const HandleDeleteGroup = async (row)=>{
  346. let res = await deleteGroupListApi(row.id)
  347. if(res?.code == 200){
  348. ElMessage.success(res?.msg)
  349. // 删除执行内容
  350. deleteFlag.value = 'success'
  351. await GetGroupList()
  352. }
  353. }
  354. // 处理分组排序
  355. const HandlTableDrag = async (val)=>{
  356. console.log('拖拽后的数据',val)
  357. // 排序后的表行数据
  358. let originData = JSON.parse(JSON.stringify(gorupTableData.value))
  359. gorupTableData.value = JSON.parse(JSON.stringify(val))
  360. let transferData = val.map((item,index)=>{
  361. return {
  362. id: item?.id,
  363. title:item.title,
  364. sortCode: index + 1,
  365. }
  366. })
  367. let res = await sortGroupListApi(transferData)
  368. if(res?.code == 200){
  369. ElMessage.success(res?.msg)
  370. await GetGroupList()
  371. }else{
  372. gorupTableData.value = [...originData]
  373. }
  374. }
  375. // 分组行禁删的条件 ====
  376. const DisabledDeleteGroupRowScene = (row,currentIndex,tableData)=>{
  377. if(row.delStatus === 0){
  378. return false
  379. }else{
  380. return true
  381. }
  382. }
  383. onMounted(async ()=>{
  384. await GetAllUserList()
  385. await GetGroupList()
  386. await GetGroupData()
  387. })
  388. </script>
  389. <style lang="scss" scoped>
  390. .container{
  391. width: 100%;
  392. overflow: auto;
  393. flex-direction: row;
  394. gap:20px;
  395. .container_left{
  396. width: 200px;
  397. :deep(.el-table__body){
  398. tr.active_row td
  399. {
  400. background-color: rgba(46, 100, 250,0.1) !important;
  401. border:none;
  402. color: #2e64fa;
  403. }
  404. }
  405. }
  406. .container_right{
  407. width: calc(100% - 220px);
  408. .content_left{
  409. line-height: 1.5;
  410. }
  411. .content_right{
  412. height: auto;
  413. align-self: flex-start;
  414. align-items: center;
  415. word-break: keep-all;
  416. flex-wrap: wrap;
  417. .button_border{
  418. font-weight: 600;
  419. }
  420. }
  421. .config_switch_desc{
  422. font-size: 14px;
  423. }
  424. .cell_container {
  425. width: 100%;
  426. height: 100%;
  427. display: flex;
  428. align-items: center;
  429. justify-content: center;
  430. text-align: center;
  431. flex-wrap: wrap;
  432. padding: 8px 0;
  433. gap: 8px;
  434. .placeholder_text,
  435. .disabled_teacher{
  436. width: 90px;
  437. height: 34px;
  438. font-weight: 400;
  439. font-size: 14px;
  440. text-align: center;
  441. line-height: 34px;
  442. background-color: #f3f3f3;
  443. border-radius: 4px;
  444. cursor: pointer;
  445. }
  446. .placeholder_text {
  447. color: #CCCCCC;
  448. }
  449. .disabled_teacher {
  450. color: #666666;
  451. }
  452. // 教师标签样式
  453. .teacher_tag {
  454. display: flex;
  455. justify-content: space-between;
  456. align-items: center;
  457. padding: 0 8px;
  458. min-width: 90px;
  459. height: 34px;
  460. font-weight: 400;
  461. font-size: 14px;
  462. color: #2E64FA;
  463. text-align: center;
  464. line-height: 34px;
  465. background: rgba(46, 100, 250, 0.1);
  466. border-radius: 4px;
  467. // 删除图标样式 (对应原 img 标签样式)
  468. .delete_icon {
  469. width: 12px;
  470. height: 12px;
  471. cursor: pointer;
  472. font-size: 12px;
  473. margin-left: 10px; /* 保留原代码中 i 标签的 margin-left 习惯 */
  474. }
  475. }
  476. }
  477. }
  478. }
  479. </style>