index.vue 7.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232
  1. <template>
  2. <div class="table-box">
  3. <ProTable ref="proTable" :columns="columns" :request-api="getTableList" :data-callback="dataCallback">
  4. <template #tableHeader>
  5. <el-button type="primary" :icon="CirclePlus" :disabled="!isAdmin" @click="handleCreate"> 新增律师 </el-button>
  6. </template>
  7. <template #operation="scope">
  8. <el-button type="primary" link :icon="EditPen" :disabled="!isAdmin" @click="handleEdit(scope.row)"> 编辑 </el-button>
  9. <el-button type="danger" link :icon="Delete" :disabled="!isAdmin" @click="handleDelete(scope.row)"> 删除 </el-button>
  10. </template>
  11. </ProTable>
  12. <LawyerDialog
  13. ref="lawyerDialogRef"
  14. :law-firm-options="lawFirmOptions"
  15. :scene-options="sceneOptions"
  16. :professional-options="professionalOptions"
  17. @success="refreshTable"
  18. />
  19. </div>
  20. </template>
  21. <script setup lang="ts">
  22. import { ref, reactive, onMounted, computed } from "vue";
  23. import { ElMessage, ElMessageBox } from "element-plus";
  24. import ProTable from "@/components/ProTable/index.vue";
  25. import type { ProTableInstance, ColumnProps } from "@/components/ProTable/interface";
  26. import {
  27. getLawyerPage,
  28. addLawyerUser,
  29. deleteLawyerUser,
  30. editLawyerUser,
  31. getLawFirmPage,
  32. getScenePage,
  33. getExpertiseAreaPage
  34. } from "@/api/modules/lawyer";
  35. import { CirclePlus, Delete, EditPen } from "@element-plus/icons-vue";
  36. import LawyerDialog from "./components/LawyerDialog.vue";
  37. import { useUserStore } from "@/stores/modules/user";
  38. const proTable = ref<ProTableInstance>();
  39. const lawyerDialogRef = ref<InstanceType<typeof LawyerDialog>>();
  40. const lawFirmOptions = ref<{ label: string; value: string | number; paymentAccount?: string }[]>([]);
  41. const sceneOptions = ref<any[]>([]);
  42. const professionalOptions = ref<{ label: string; value: string | number }[]>([]);
  43. const userStore = useUserStore();
  44. const isAdmin = computed(() => userStore.userInfo?.name === "admin");
  45. const loginFirmId = computed(() => userStore.userInfo?.roleId || "");
  46. const ensureAdmin = () => {
  47. if (isAdmin.value) return true;
  48. ElMessage.warning("仅管理员可使用该功能");
  49. return false;
  50. };
  51. const columns = reactive<ColumnProps<any>[]>([
  52. { label: "序号", type: "index", width: 60, align: "center" },
  53. { label: "律师姓名", prop: "name", width: 140, search: { el: "input", props: { placeholder: "请输入律师姓名" } } },
  54. { label: "联系电话", prop: "phone", width: 140, search: { el: "input", props: { placeholder: "请输入联系电话" } } },
  55. {
  56. label: "从业时间",
  57. prop: "practiceStartDate",
  58. width: 140,
  59. search: {
  60. el: "date-picker",
  61. props: {
  62. type: "date",
  63. valueFormat: "YYYY-MM-DD",
  64. placeholder: "请选择从业时间"
  65. }
  66. }
  67. },
  68. // { label: "专业领域", prop: "expertiseAreaInfo" },
  69. { label: "法律场景", prop: "firstLevelScenario" },
  70. {
  71. label: "接单状态",
  72. prop: "status",
  73. width: 120,
  74. tag: true,
  75. enum: [
  76. { label: "接单中", value: 1, tagType: "success" },
  77. { label: "暂停接单", value: 0, tagType: "info" }
  78. ],
  79. fieldNames: { label: "label", value: "value" }
  80. },
  81. { label: "收款账号", prop: "paymentNum", width: 220 },
  82. { label: "所属律所", prop: "firmName", width: 220 },
  83. { label: "操作", prop: "operation", width: 200, fixed: "right" }
  84. ]);
  85. const getTableList = async (params: any) => {
  86. const newParams: Record<string, any> = { ...params, page: params.pageNum, size: params.pageSize };
  87. delete newParams.pageNum;
  88. delete newParams.pageSize;
  89. if (!isAdmin.value && loginFirmId.value) {
  90. newParams.firmId = loginFirmId.value;
  91. }
  92. return getLawyerPage(newParams);
  93. };
  94. const dataCallback = (data: any) => ({
  95. list: data.records,
  96. total: data.total
  97. });
  98. const refreshTable = () => {
  99. proTable.value?.getTableList();
  100. };
  101. const handleCreate = () => {
  102. if (!ensureAdmin()) return;
  103. lawyerDialogRef.value?.open({
  104. title: "新增律师",
  105. onSubmit: async payload => {
  106. let params = {
  107. name: payload.name,
  108. phone: payload.phone,
  109. practiceStartDate: payload.practiceStartDate,
  110. firstLevelScenario: payload.firstLevelScenario,
  111. status: payload.status,
  112. paymentNum: payload.paymentNum,
  113. lawFirmId: payload.lawFirmId
  114. };
  115. await addLawyerUser(params);
  116. ElMessage.success("新增成功");
  117. refreshTable();
  118. }
  119. });
  120. };
  121. const handleEdit = (row: any) => {
  122. if (!ensureAdmin()) return;
  123. lawyerDialogRef.value?.open({
  124. title: "编辑律师",
  125. row,
  126. onSubmit: async payload => {
  127. let params = {
  128. id: payload.id,
  129. name: payload.name,
  130. phone: payload.phone,
  131. practiceStartDate: payload.practiceStartDate,
  132. firstLevelScenario: payload.firstLevelScenario,
  133. status: payload.status,
  134. paymentNum: payload.paymentNum,
  135. lawFirmId: payload.lawFirmId
  136. };
  137. await editLawyerUser(params);
  138. ElMessage.success("编辑成功");
  139. refreshTable();
  140. }
  141. });
  142. };
  143. const handleDelete = (row: any) => {
  144. if (!ensureAdmin()) return;
  145. ElMessageBox.confirm(`确定删除律师【${row.userName}】吗?`, "提示", {
  146. type: "warning"
  147. })
  148. .then(async () => {
  149. await deleteLawyerUser({ id: row.id });
  150. ElMessage.success("删除成功");
  151. refreshTable();
  152. })
  153. .catch(() => {});
  154. };
  155. const fetchLawFirmOptions = async () => {
  156. try {
  157. const res: any = await getLawFirmPage({ page: 1, size: 999 });
  158. const listSource = res.data.records || [];
  159. lawFirmOptions.value = listSource.map((item: any) => ({
  160. label: item.firmName,
  161. value: item.id,
  162. paymentAccount: item.paymentAccount
  163. }));
  164. } catch (error) {
  165. console.error("获取律所列表失败", error);
  166. lawFirmOptions.value = [];
  167. }
  168. };
  169. const buildSceneTree = (list: any[] = []) => {
  170. const map = new Map<string | number, any>();
  171. const roots: any[] = [];
  172. list.forEach(item => {
  173. map.set(item.id, { ...item, children: [] });
  174. });
  175. list.forEach(item => {
  176. const current = map.get(item.id);
  177. if (item.parentId && map.has(item.parentId)) {
  178. map.get(item.parentId).children.push(current);
  179. } else {
  180. roots.push(current);
  181. }
  182. });
  183. return roots;
  184. };
  185. const fetchSceneOptions = async () => {
  186. try {
  187. const res: any = await getScenePage({ page: 1, size: 999 });
  188. const list = res?.records || res?.data?.records || [];
  189. sceneOptions.value = buildSceneTree(list);
  190. } catch (error) {
  191. console.error("获取法律场景失败", error);
  192. sceneOptions.value = [];
  193. }
  194. };
  195. const fetchProfessionalOptions = async () => {
  196. try {
  197. const res: any = await getExpertiseAreaPage({ page: 1, size: 999 });
  198. const list = res?.records || res?.data?.records || [];
  199. professionalOptions.value = list.map((item: any) => ({
  200. label: item.expertiseAreaInfo,
  201. value: item.id
  202. }));
  203. } catch (error) {
  204. console.error("获取专业领域失败", error);
  205. professionalOptions.value = [];
  206. }
  207. };
  208. onMounted(() => {
  209. fetchLawFirmOptions();
  210. fetchSceneOptions();
  211. fetchProfessionalOptions();
  212. refreshTable();
  213. });
  214. </script>
  215. <style scoped lang="scss"></style>