index.tsx 9.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339
  1. import {
  2. DataTableColumn,
  3. NButton,
  4. NCascader,
  5. NDataTable,
  6. NForm,
  7. NFormItem,
  8. NIcon,
  9. NImage,
  10. NInput,
  11. NModal,
  12. NSpace,
  13. useDialog,
  14. useMessage
  15. } from 'naive-ui';
  16. import { defineComponent, onMounted, reactive } from 'vue';
  17. import styles from './index.module.less';
  18. import { useUserStore } from '/src/store/modules/users';
  19. import UploadFile from '/src/components/upload-file';
  20. import { Add } from '@vicons/ionicons5';
  21. import {
  22. api_schoolUpdate,
  23. api_sysAreaQueryAllProvince,
  24. api_teacherPage,
  25. api_tenantInfoUpdateStatus,
  26. api_userResetPassword
  27. } from '../../api';
  28. import AddTeacher from '../../modal/add-teacher';
  29. import TheQrCode from '/src/components/TheQrCode';
  30. import { stringifyQuery } from '/src/router';
  31. export default defineComponent({
  32. name: 'school-info',
  33. setup() {
  34. const user = useUserStore();
  35. const formOptions = reactive({
  36. areaList: [] as any[]
  37. });
  38. const forms = reactive({
  39. name: user.info.schoolInfos?.[0]?.name,
  40. logo: user.info.schoolInfos?.[0]?.logo || user.info.avatar,
  41. provinceCode: user.info.schoolInfos?.[0]?.provinceCode || '', // 省份编码
  42. cityCode: user.info.schoolInfos?.[0]?.cityCode || '', // 城市编码
  43. regionCode: user.info.schoolInfos?.[0]?.regionCode || '' // 区域编码
  44. });
  45. const data = reactive({
  46. loading: false,
  47. schoolLoading: true,
  48. dataList: [] as any[],
  49. disabled: true,
  50. modal: false,
  51. qrModal: false
  52. });
  53. const columns = (): DataTableColumn[] => {
  54. return [
  55. {
  56. title: '老师姓名',
  57. key: 'nickname'
  58. },
  59. {
  60. title: '手机号码',
  61. key: 'phone'
  62. },
  63. {
  64. title: '性别',
  65. key: 'questionTypeCode',
  66. render: (row: any) => {
  67. return <div>{row.gender ? '男' : '女'}</div>;
  68. }
  69. },
  70. {
  71. title: '状态',
  72. key: 'statusName',
  73. render: (row: any) => {
  74. return (
  75. <div>
  76. {row.status === 'ACTIVATION' ? (
  77. <NButton text>{row.statusName}</NButton>
  78. ) : (
  79. <NButton class={styles.errorBtn} text>
  80. {row.statusName}
  81. </NButton>
  82. )}
  83. </div>
  84. );
  85. }
  86. },
  87. {
  88. title: '操作',
  89. key: 'titleImg',
  90. render: (row: any) => (
  91. <NSpace>
  92. <NButton
  93. type="primary"
  94. quaternary
  95. size="small"
  96. onClick={() => onResetPassword(row)}>
  97. 重置密码
  98. </NButton>
  99. {row.status === 'ACTIVATION' ? (
  100. <NButton
  101. type="primary"
  102. quaternary
  103. size="small"
  104. onClick={() => handleChange(row)}>
  105. 冻结
  106. </NButton>
  107. ) : (
  108. <NButton
  109. class={styles.errorBtn}
  110. quaternary
  111. size="small"
  112. onClick={() => handleChange(row)}>
  113. 解冻
  114. </NButton>
  115. )}
  116. </NSpace>
  117. )
  118. }
  119. ];
  120. };
  121. const getAreaList = async () => {
  122. const res = await api_sysAreaQueryAllProvince();
  123. if (res?.code === 200) {
  124. formOptions.areaList = res.data;
  125. }
  126. };
  127. const getList = async () => {
  128. data.loading = true;
  129. const res = await api_teacherPage({
  130. schoolId: user.info.schoolInfos?.[0]?.id,
  131. // jobType: 'TEACHER',
  132. // jobType: 'ADMIN',
  133. page: 1,
  134. rows: 1000
  135. });
  136. data.loading = false;
  137. if (res?.code === 200 && Array.isArray(res?.data?.rows)) {
  138. data.dataList = res.data.rows;
  139. }
  140. };
  141. onMounted(() => {
  142. getAreaList();
  143. getList();
  144. });
  145. const dialog = useDialog();
  146. const message = useMessage();
  147. const handleChange = (row: any) => {
  148. const statuStr = row.status === 'LOCKED' ? '解冻' : '冻结';
  149. dialog.warning({
  150. title: '温馨提示',
  151. content: `是否${statuStr}"${row.nickname}"?`,
  152. positiveText: '确定',
  153. negativeText: '取消',
  154. onPositiveClick: async () => {
  155. await api_tenantInfoUpdateStatus({
  156. ids: [row.id],
  157. status: row.status === 'LOCKED' ? 'ACTIVATION' : 'LOCKED'
  158. });
  159. getList();
  160. message.success(statuStr + '成功');
  161. }
  162. });
  163. };
  164. // 重置密码
  165. const onResetPassword = (row: any): void => {
  166. dialog.warning({
  167. title: '警告',
  168. content: `重置"${row.nickname}"的密码,是否继续?`,
  169. positiveText: '确定',
  170. negativeText: '取消',
  171. onPositiveClick: async () => {
  172. await api_userResetPassword({
  173. userId: row.id,
  174. password: 'ktyq' + row.phone.substr(7),
  175. clientType: 'TEACHER'
  176. });
  177. message.success('重置成功');
  178. }
  179. });
  180. };
  181. const changeSchoolInfo = async () => {
  182. data.schoolLoading = false;
  183. await api_schoolUpdate({ ...user.info.schoolInfos?.[0], ...forms });
  184. data.schoolLoading = true;
  185. message.success('修改成功');
  186. data.disabled = true;
  187. };
  188. const registerUrl = () => {
  189. const queryStr = `tenantId=${user.info.schoolInfos?.[0]?.tenantId}&schoolId=${user.info.schoolInfos?.[0]?.id}&schoolName=${user.info.schoolInfos?.[0]?.name}`;
  190. const url =
  191. `${location.origin}/classroom-app/#/teaher-register?` + queryStr;
  192. console.log(url);
  193. return url;
  194. };
  195. return () => (
  196. <div class={styles.schoolInfo}>
  197. <NSpace wrapItem={false} align="center">
  198. <div class={styles.logo}>
  199. <NImage
  200. previewDisabled={false}
  201. width={100}
  202. height={100}
  203. src={forms.logo}
  204. />
  205. <div
  206. style={{ display: data.disabled ? 'none' : '' }}
  207. class={styles.changeHead}>
  208. 修改头像
  209. {data.schoolLoading && (
  210. <UploadFile
  211. class={[styles.uploadFile]}
  212. cropper
  213. onUpdate:fileList={val => {
  214. forms.logo = val;
  215. }}
  216. />
  217. )}
  218. </div>
  219. </div>
  220. <NForm
  221. model={forms}
  222. style={{ paddingTop: '30px' }}
  223. disabled={data.disabled}>
  224. <NSpace>
  225. <NFormItem
  226. label="学校名称"
  227. path="name"
  228. showRequireMark={false}
  229. rule={[
  230. { required: true, message: '请填写学习名称', trigger: 'blur' }
  231. ]}>
  232. <NInput
  233. class={styles.input}
  234. maxlength={20}
  235. v-model:value={forms.name}
  236. />
  237. </NFormItem>
  238. <NFormItem label="城区" style={{ width: '300px' }}>
  239. <NCascader
  240. options={formOptions.areaList}
  241. labelField="name"
  242. valueField="code"
  243. childrenField="areas"
  244. checkStrategy="child"
  245. expandTrigger="hover"
  246. defaultValue={
  247. user.info.schoolInfos?.[0]?.regionCode ||
  248. user.info.schoolInfos?.[0]?.cityCode
  249. }
  250. onUpdate:value={(val: any, option: any, pathValues: any) => {
  251. forms.provinceCode = pathValues[0]?.code;
  252. forms.cityCode = pathValues[1]?.code;
  253. forms.regionCode = pathValues[2]?.code;
  254. }}
  255. />
  256. </NFormItem>
  257. <NFormItem>
  258. {data.disabled ? (
  259. <NSpace class={styles.btnList} align="center" justify="end">
  260. <NButton
  261. class={styles.btn}
  262. color="#f24433"
  263. onClick={() => (data.disabled = false)}>
  264. 修改信息
  265. </NButton>
  266. </NSpace>
  267. ) : (
  268. <NSpace class={styles.btnList} align="center" justify="end">
  269. <NButton
  270. class={styles.btn}
  271. onClick={() => (data.disabled = true)}>
  272. 取消
  273. </NButton>
  274. <NButton
  275. class={styles.btn}
  276. loading={!data.schoolLoading}
  277. type="primary"
  278. onClick={() => changeSchoolInfo()}>
  279. 完成
  280. </NButton>
  281. </NSpace>
  282. )}
  283. </NFormItem>
  284. </NSpace>
  285. </NForm>
  286. </NSpace>
  287. <NSpace style={{ padding: '32px 0' }}>
  288. <NButton
  289. type="primary"
  290. renderIcon={() => <NIcon component={<Add />} />}
  291. onClick={() => (data.modal = true)}>
  292. 添加老师
  293. </NButton>
  294. <NButton type="primary" onClick={() => (data.qrModal = true)}>
  295. 老师注册二维码
  296. </NButton>
  297. </NSpace>
  298. <NDataTable
  299. loading={data.loading}
  300. columns={columns()}
  301. data={data.dataList}></NDataTable>
  302. <NModal
  303. class={styles.addTeacher}
  304. v-model:show={data.modal}
  305. title="添加老师"
  306. preset="dialog"
  307. showIcon={false}>
  308. <AddTeacher
  309. onClose={() => {
  310. data.modal = false;
  311. getList();
  312. }}
  313. />
  314. </NModal>
  315. <NModal
  316. v-model:show={data.qrModal}
  317. title="二维码"
  318. preset="dialog"
  319. showIcon={false}>
  320. <div style={{ textAlign: 'center' }}>
  321. <TheQrCode text={registerUrl()} size={300} />
  322. </div>
  323. </NModal>
  324. </div>
  325. );
  326. }
  327. });