complete-profile.vue 10.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298
  1. <template>
  2. <div class="fx-column">
  3. <div class="notice pb40">*账号信息安全与您本人息息相关,请如实填写</div>
  4. <div class="fx-column" style="height: 420px; overflow-y:scroll">
  5. <el-form ref="form" :model="formData" :rules="formRules" :validate-on-rule-change="false" label-position="right"
  6. label-width="70px">
  7. <el-row :gutter="20">
  8. <el-col :span="24">
  9. <el-form-item prop="username" label="姓 名">
  10. <el-input type="text" v-model="formData.username" placeholder="请输入姓名"></el-input>
  11. </el-form-item>
  12. </el-col>
  13. <!-- 暂时不需要学年,学年从年级上选择 -->
  14. <el-col v-if="false" :span="10">
  15. <el-form-item prop="year" label="学 年">
  16. <el-select v-model="formData.year" placeholder="请选择学年">
  17. <el-option v-for="(y, idx) in yearOptions" :key="idx" :label="y" :value="y"></el-option>
  18. </el-select>
  19. </el-form-item>
  20. </el-col>
  21. </el-row>
  22. <el-row :gutter="20">
  23. <el-col :span="isFrontTeacher?14:24">
  24. <el-form-item prop="schoolId" label="学 校">
  25. <el-select v-model="formData.schoolId" placeholder="请选择学校" @change="handleSchoolChange" class="width100">
  26. <el-option-group v-for="(g, index) in groupedSchoolOptions" :key="index" :label="g.label">
  27. <el-option v-for="(sc,idx) in g.options" :key="idx" :label="sc.schoolName"
  28. :value="sc.schoolId"></el-option>
  29. </el-option-group>
  30. </el-select>
  31. </el-form-item>
  32. </el-col>
  33. <el-col v-if="isFrontTeacher" :span="10">
  34. <el-form-item prop="subjectid" label="科 目">
  35. <el-select v-model="formData.subjectid" placeholder="请选择科目" class="width100">
  36. <el-option v-for="(sj,idx) in subjectOptions" :key="idx" :label="sj.label"
  37. :value="sj.value"></el-option>
  38. </el-select>
  39. </el-form-item>
  40. </el-col>
  41. </el-row>
  42. <el-row :gutter="20">
  43. <el-col :span="12">
  44. <el-form-item v-if="isFrontStudent" prop="sno" label="学 号">
  45. <el-input type="text" v-model="formData.sno" placeholder="请输入学号"></el-input>
  46. </el-form-item>
  47. </el-col>
  48. <el-col :span="12">
  49. <el-form-item v-if="isFrontStudent" prop="clazzId" label="班 级">
  50. <el-cascader
  51. v-model="formData.clazzId"
  52. :disabled="!formData.schoolId"
  53. :placeholder="formData.schoolId?'选择年级-班级':'请先选择学校'"
  54. :options="classTree"
  55. ></el-cascader>
  56. </el-form-item>
  57. </el-col>
  58. </el-row>
  59. <template v-if="isFrontTeacher">
  60. <!-- 这里的name另外定义了一个,因为内部for循环+v-model方式会引发循环赋值(uni-app的实现问题) -->
  61. <el-form-item prop="gradeClass" label="年级组">
  62. <el-cascader
  63. v-model="formData.gradeClass"
  64. :disabled="!formData.schoolId"
  65. :options="classTree"
  66. :placeholder="formData.schoolId?'选择年级组':'请先选择学校'"
  67. :props="{multiple:true}"
  68. class="width100"
  69. ></el-cascader>
  70. </el-form-item>
  71. <el-row :gutter="20">
  72. <el-col :span="6">
  73. <el-form-item prop="isHeadteacher" label="班主任">
  74. <el-switch v-model="formData.isHeadteacher"></el-switch>
  75. </el-form-item>
  76. </el-col>
  77. <el-col :span="18">
  78. <el-form-item v-if="formData.isHeadteacher" prop="headteacherClassId" label="带 班" required>
  79. <el-cascader
  80. :disabled="!formData.schoolId"
  81. :options="classTree"
  82. v-model="formData.headteacherClassId"
  83. :placeholder="formData.schoolId?'选择年级-班级':'请先选择学校'"
  84. :props="{emitPath: false}"
  85. class="width100"
  86. ></el-cascader>
  87. </el-form-item>
  88. </el-col>
  89. </el-row>
  90. </template>
  91. <el-row :gutter="20">
  92. <el-col :span="11">
  93. <el-form-item prop="phoneNumber" label="手机号">
  94. <el-input type="text" v-model="formData.phoneNumber" placeholder="请输入手机号码"></el-input>
  95. </el-form-item>
  96. </el-col>
  97. <el-col :span="13">
  98. <el-form-item prop="code" label="验证码">
  99. <div class="fx-row fx-bet-cen">
  100. <el-input type="text" v-model="formData.code" placeholder="请输入验证码" class="fx-1"></el-input>
  101. <el-button
  102. type="primary"
  103. class="mx-send"
  104. :class="{'inactive':countdown>0}"
  105. @click="handleSendSms"
  106. >{{ countdown > 0 ? `(${countdown})秒` : '获取' }}
  107. </el-button>
  108. </div>
  109. </el-form-item>
  110. </el-col>
  111. </el-row>
  112. </el-form>
  113. <div class="fx-row fx-cen-cen pt20 pb40">
  114. <el-button type="primary" @click="handleSubmit" style="width: 180px" round v-loading="loading">保存</el-button>
  115. </div>
  116. </div>
  117. </div>
  118. </template>
  119. <script>
  120. import auth from '@/utils/auth'
  121. import config from '@/common/mx-config.js'
  122. import transferMixin from '@/components/mx-transfer-mixin.js'
  123. import userValidateMixin from '@/views/components/user-validation-mixin.js'
  124. import { getSubjectsList } from '@/api/webApi/system'
  125. import { getAllGradeClasses } from '@/api/webApi/grade'
  126. import { getAreaSchoolAndYears, improveUserInfo, sendSms, validateSms } from '@/api/login'
  127. import { mapGetters } from 'vuex'
  128. export default {
  129. mixins: [transferMixin, userValidateMixin],
  130. data() {
  131. return {
  132. formData: {
  133. username: '',
  134. // sex: '',
  135. // region: '',
  136. year: '',
  137. gradeId: '',
  138. clazzId: '',
  139. subjectid: '',
  140. phoneNumber: '',
  141. code: '',
  142. schoolId: '',
  143. gradeClass: null,
  144. //
  145. sno: '',
  146. isHeadteacher: false,
  147. headteacherClassId: ''
  148. },
  149. // 选项
  150. loading: false,
  151. countdown: 0,
  152. timer: null,
  153. sexOptions: config.form.sexOptions,
  154. schoolOptions: [],
  155. yearOptions: [],
  156. subjectOptions: [],
  157. yesOrNoOptions: config.form.yesOrNoOptions
  158. }
  159. },
  160. computed: {
  161. ...mapGetters(['isFrontTeacher', 'isFrontStudent']),
  162. formRules() {
  163. return this.extractUserRules(this.formData)
  164. },
  165. groupedSchoolOptions() {
  166. return this.schoolOptions.groupBy(
  167. (sc) => sc.area,
  168. 'label',
  169. 'options'
  170. )
  171. }
  172. },
  173. mounted() {
  174. this.loadData()
  175. },
  176. beforeDestroy() {
  177. this.releaseTimer()
  178. },
  179. methods: {
  180. loadData() {
  181. // 初始可加载学校、学年、科目数据
  182. getAreaSchoolAndYears().then((res) => {
  183. this.schoolOptions = res.data.schools
  184. this.yearOptions = res.data.years
  185. })
  186. getSubjectsList().then((res) => {
  187. this.subjectOptions = res.rows.map((s) => ({
  188. label: s.subjectname,
  189. value: s.subjectid
  190. }))
  191. })
  192. },
  193. reloadClassTree() {
  194. if (!this.formData.schoolId) return
  195. getAllGradeClasses({
  196. schoolId: this.formData.schoolId
  197. }).then((res) => {
  198. this.formData.gradeClass = {}
  199. this.rawClassTree = res.data
  200. // 挂载动态属性,用于表单校验
  201. this.rawClassTree.forEach(
  202. (grade) => (this.formData.gradeClass[grade.name] = [])
  203. )
  204. })
  205. },
  206. handleSchoolChange(e) {
  207. this.reloadClassTree()
  208. },
  209. handleSendSms() {
  210. if (this.countdown > 0) return // in lock
  211. this.$refs.form.clearValidate() // 需要传空数组
  212. this.$refs.form.validateField(['phoneNumber'], (err) => {
  213. if (err) return
  214. this.beginCountDown()
  215. sendSms({
  216. mobile: this.formData.phoneNumber,
  217. smsType: 1
  218. }).then((res) => {
  219. this.msgSuccess('验证码已发送')
  220. })
  221. })
  222. },
  223. handleSubmit() {
  224. this.$refs.form.validate().then((_) => {
  225. this.loading = true
  226. const validateData = {
  227. mobile: this.formData.phoneNumber,
  228. code: this.formData.code
  229. }
  230. validateSms(validateData)
  231. .then((_) => {
  232. // 从formData到提交结构还需要轻微转换
  233. const postData = this.formDataToPostData(
  234. this.formData,
  235. this.rawClassTree
  236. )
  237. console.log(
  238. 'sms code valid & will post data',
  239. postData
  240. )
  241. improveUserInfo(postData)
  242. .then((res) => {
  243. // reset login token
  244. auth.setToken(res.data.token)
  245. this.$store.dispatch('GetInfo').then((_) => {
  246. // to index page
  247. this.$emit('completed')
  248. })
  249. })
  250. .finally(() => this.loading = false)
  251. })
  252. .finally(() => this.loading = false)
  253. })
  254. },
  255. beginCountDown() {
  256. this.releaseTimer()
  257. this.countdown = 90
  258. this.timer = setInterval((_) => {
  259. if (this.countdown == 0) {
  260. this.releaseTimer()
  261. } else {
  262. this.countdown -= 1
  263. }
  264. }, 1000)
  265. },
  266. releaseTimer() {
  267. if (this.timer) {
  268. clearInterval(this.timer)
  269. this.timer = null
  270. }
  271. }
  272. }
  273. }
  274. </script>
  275. <style scoped>
  276. .notice {
  277. color: #f88f7b;
  278. font-size: 26 rpx;
  279. text-align: center;
  280. }
  281. .mx-send {
  282. width: 60px;
  283. margin-left: 10px;
  284. display: flex;
  285. justify-content: center;
  286. align-items: center;
  287. }
  288. .mx-send.inactive {
  289. background-color: #aaaaaa;
  290. border-color: #aaaaaa;
  291. }
  292. </style>