ModifyMarkerBind.vue 11 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385
  1. <template>
  2. <el-dialog
  3. class="modify-marker-bind modify-marker-question"
  4. :visible.sync="modalIsShow"
  5. append-to-body
  6. top="10px"
  7. width="900px"
  8. title="绑定评卷员"
  9. :close-on-click-modal="false"
  10. :close-on-press-escape="false"
  11. :show-close="false"
  12. @opened="visibleChange"
  13. >
  14. <el-row type="flex" :gutter="10">
  15. <el-col :span="12">
  16. <div class="marker-box">
  17. <div class="user-title">评卷员</div>
  18. <div class="user-search">
  19. <el-input
  20. v-model.trim="filterLabel"
  21. placeholder="请输入评卷员名称"
  22. clearable
  23. size="mini"
  24. prefix-icon="el-icon-search"
  25. @input="labelChange"
  26. ></el-input>
  27. </div>
  28. <div class="user-types">
  29. <div
  30. :class="['user-type', { 'is-active': isOrgTab }]"
  31. @click="switchUserType('org')"
  32. >
  33. 组织架构
  34. </div>
  35. <div
  36. :class="['user-type', { 'is-active': !isOrgTab }]"
  37. @click="switchUserType('course')"
  38. >
  39. 课程
  40. </div>
  41. </div>
  42. <div class="user-tree">
  43. <el-tree
  44. ref="UserTree"
  45. :data="userTree"
  46. node-key="id"
  47. :default-checked-keys="selectedUserIds"
  48. :props="defaultProps"
  49. :default-expand-all="!isOrgTab"
  50. :default-expanded-keys="isOrgTab ? userOrgKeys : []"
  51. >
  52. <span class="custom-tree-node" slot-scope="{ node, data }">
  53. <el-checkbox
  54. v-if="data.isUser"
  55. v-model="node.checked"
  56. :disabled="checkNodeDisabled(data)"
  57. @change="(val) => userChange(val, data)"
  58. >
  59. {{ node.label }}({{ data.loginName }})
  60. </el-checkbox>
  61. <span v-else>{{ node.label }}</span>
  62. <div title="全选" @click.stop>
  63. <el-checkbox
  64. v-if="!data.isUser && data.children.length"
  65. v-model="data.selected"
  66. @change="(checked) => selectNodeAll(checked, data)"
  67. ></el-checkbox>
  68. </div>
  69. </span>
  70. </el-tree>
  71. </div>
  72. </div>
  73. </el-col>
  74. <el-col :span="12">
  75. <div class="marker-box marker-box-uq">
  76. <el-form
  77. ref="modalFormRef"
  78. :rules="rules"
  79. :model="{}"
  80. label-width="100px"
  81. label-position="top"
  82. >
  83. <el-form-item prop="users" label="已选评卷员:">
  84. <el-tag
  85. v-for="user in selectedUsers"
  86. :key="user.id"
  87. :closable="!checkNodeDisabled(user)"
  88. :disable-transitions="false"
  89. @close="toDeleteUser(user)"
  90. >
  91. {{ user.name }}({{ user.loginName }})
  92. </el-tag>
  93. </el-form-item>
  94. </el-form>
  95. </div>
  96. </el-col>
  97. </el-row>
  98. <div class="marker-footer">
  99. <el-button type="primary" @click="confirm">确认</el-button>
  100. <el-button @click="cancel">取消</el-button>
  101. </div>
  102. <div slot="footer"></div>
  103. </el-dialog>
  104. </template>
  105. <script>
  106. import { deepCopy } from "@/plugins/utils";
  107. import { organizationList } from "../../../base/api";
  108. import { markMarkerBindList } from "../../api";
  109. export default {
  110. name: "modify-mark-group",
  111. props: {
  112. data: {
  113. type: Object,
  114. default() {
  115. return {};
  116. },
  117. },
  118. courseId: {
  119. type: String,
  120. default: "",
  121. },
  122. },
  123. data() {
  124. const usersValidator = (rule, value, callback) => {
  125. if (!this.selectedUserIds.length) {
  126. callback(new Error("请选择评卷员"));
  127. } else {
  128. callback();
  129. }
  130. };
  131. return {
  132. modalIsShow: false,
  133. filterLabel: "",
  134. userType: "course",
  135. courseUsers: [],
  136. orgUsers: [],
  137. userTree: [],
  138. userList: [],
  139. selectedUsers: [],
  140. disabledUserIds: [],
  141. selectedUserIds: [],
  142. userOrgKeys: [this.$ls.get("orgId")],
  143. defaultProps: {
  144. children: "children",
  145. label: "label",
  146. },
  147. rules: {
  148. users: [
  149. {
  150. required: true,
  151. validator: usersValidator,
  152. trigger: "change",
  153. },
  154. ],
  155. },
  156. };
  157. },
  158. computed: {
  159. isOrgTab() {
  160. return this.userType === "org";
  161. },
  162. },
  163. mounted() {
  164. this.getOrgData();
  165. },
  166. methods: {
  167. async visibleChange() {
  168. this.filterLabel = "";
  169. this.userType = "course";
  170. const res = await markMarkerBindList(this.data);
  171. this.selectedUserIds = res || [];
  172. this.disabledUserIds = [...this.selectedUserIds];
  173. this.labelChange();
  174. this.$nextTick(() => {
  175. const users = this.$refs.UserTree.getCheckedNodes(true);
  176. this.selectedUsers = users;
  177. });
  178. },
  179. checkNodeDisabled(data) {
  180. return this.disabledUserIds.includes(data.id);
  181. },
  182. cancel() {
  183. this.modalIsShow = false;
  184. this.$emit("cancel");
  185. },
  186. open() {
  187. this.modalIsShow = true;
  188. },
  189. // user
  190. switchUserType(type) {
  191. this.filterLabel = "";
  192. this.userType = type;
  193. this.userTree =
  194. type === "org" ? deepCopy(this.orgUsers) : deepCopy(this.courseUsers);
  195. this.$refs.UserTree.setCheckedKeys(this.selectedUserIds);
  196. },
  197. async getOrgData() {
  198. let params = {
  199. specialPrivilege: "MARKER",
  200. };
  201. if (this.courseId) params.courseId = this.courseId;
  202. const data = await organizationList(params);
  203. this.parseUserData(data);
  204. this.getUserList();
  205. },
  206. parseUserData(data) {
  207. const parseUser = (list) => {
  208. return list.map((item) => {
  209. // org
  210. let nitem = {
  211. id: item.id,
  212. label: item.name,
  213. isUser: false,
  214. selected: false,
  215. children: [],
  216. };
  217. if (item["children"] && item["children"].length) {
  218. nitem.children = [...nitem.children, ...parseUser(item.children)];
  219. }
  220. // user
  221. if (item["sysUserList"] && item["sysUserList"].length) {
  222. let sysUserList = item.sysUserList;
  223. const users = sysUserList.map((user) => {
  224. const nuser = {
  225. id: user.id,
  226. userId: user.id,
  227. label: user.realName,
  228. name: user.realName,
  229. orgName: item.name,
  230. loginName: user.loginName,
  231. selected: false,
  232. isUser: true,
  233. };
  234. return nuser;
  235. });
  236. nitem.children = [...nitem.children, ...users];
  237. }
  238. if (item["courseUserList"] && item["courseUserList"].length) {
  239. nitem.courseUserList = item.courseUserList.map((user) => {
  240. return {
  241. id: user.id,
  242. userId: user.id,
  243. label: user.realName,
  244. name: user.realName,
  245. orgName: user.orgName,
  246. loginName: user.loginName,
  247. selected: false,
  248. isUser: true,
  249. };
  250. });
  251. }
  252. return nitem;
  253. });
  254. };
  255. this.orgUsers = parseUser(data);
  256. this.userTree = deepCopy(this.orgUsers);
  257. if (this.courseId && this.orgUsers[0].courseUserList) {
  258. this.courseUsers = deepCopy(this.orgUsers[0].courseUserList);
  259. }
  260. this.getUserList();
  261. },
  262. getUserList() {
  263. let userList = [];
  264. const fetchUser = (users) => {
  265. users.forEach((item) => {
  266. if (item["children"] && item["children"].length) {
  267. fetchUser(item.children);
  268. } else {
  269. if (item.isUser) {
  270. let nitem = { ...item };
  271. nitem.label = `${nitem.name}`;
  272. userList.push(nitem);
  273. }
  274. }
  275. });
  276. };
  277. fetchUser(this.orgUsers);
  278. this.userList = userList;
  279. },
  280. labelChange() {
  281. if (!this.filterLabel) {
  282. this.switchUserType(this.userType);
  283. } else {
  284. const escapeRegexpString = (value = "") =>
  285. String(value).replace(/[|\\{}()[\]^$+*?.]/g, "\\$&");
  286. const reg = new RegExp(escapeRegexpString(this.filterLabel), "i");
  287. if (this.userType === "org") {
  288. this.userTree = this.userList.filter((item) => reg.test(item.name));
  289. } else {
  290. this.userTree = this.courseUsers.filter((item) =>
  291. reg.test(item.name)
  292. );
  293. }
  294. }
  295. this.$refs.UserTree.setCheckedKeys(this.selectedUserIds);
  296. },
  297. selectNodeAll(checked, data) {
  298. let users = [];
  299. const getUserIds = (list) => {
  300. list.forEach((item) => {
  301. item.selected = checked;
  302. if (item.children && item.children.length) {
  303. getUserIds(item.children);
  304. } else {
  305. if (item.isUser) users.push(item);
  306. }
  307. });
  308. };
  309. getUserIds(data.children);
  310. const userIds = users.map((u) => u.id);
  311. const selectedUserIds = this.selectedUsers.map((item) => item.id);
  312. let deleteUserIds = [];
  313. userIds.forEach((userId, uindex) => {
  314. const userPos = selectedUserIds.indexOf(userId);
  315. const includeUser = userPos !== -1;
  316. if (checked) {
  317. if (!includeUser) this.selectedUsers.push(users[uindex]);
  318. } else {
  319. if (includeUser) {
  320. deleteUserIds.push(userId);
  321. }
  322. }
  323. });
  324. this.selectedUsers = this.selectedUsers.filter(
  325. (u) => !deleteUserIds.includes(u.id)
  326. );
  327. this.selectedUserIds = this.selectedUsers.map((item) => item.id);
  328. this.$refs.UserTree.setCheckedKeys(this.selectedUserIds);
  329. this.$refs.modalFormRef.validateField("users");
  330. },
  331. updateSelectedUsersFromUserIds() {
  332. this.selectedUsers = this.userList.filter((user) =>
  333. this.selectedUserIds.includes(user.id)
  334. );
  335. },
  336. userChange(checked, user) {
  337. if (checked) {
  338. this.selectedUsers.push(user);
  339. } else {
  340. this.selectedUsers = this.selectedUsers.filter(
  341. (item) => item.id !== user.id
  342. );
  343. }
  344. this.selectedUserIds = this.selectedUsers.map((item) => item.id);
  345. this.$refs.modalFormRef.validateField("users");
  346. },
  347. toDeleteUser(user) {
  348. const pos = this.selectedUsers.findIndex((item) => item.id === user.id);
  349. this.selectedUsers.splice(pos, 1);
  350. this.selectedUserIds = this.selectedUsers.map((item) => item.id);
  351. this.$refs.UserTree.setCheckedKeys(this.selectedUserIds);
  352. this.$refs.modalFormRef.validateField("users");
  353. },
  354. // confirm
  355. async confirm() {
  356. const valid = await this.$refs.modalFormRef.validate().catch(() => {});
  357. if (!valid) return;
  358. this.$emit(
  359. "modified",
  360. this.selectedUsers.map((item) => {
  361. return {
  362. id: item.id,
  363. name: item.name,
  364. };
  365. })
  366. );
  367. this.modalIsShow = false;
  368. },
  369. },
  370. };
  371. </script>