SelectQuestionTeacher.vue 11 KB

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