ソースを参照

飞行学院 学生端

husky 5 ヶ月 前
コミット
6ed312820d

+ 2 - 2
.env.development

@@ -6,8 +6,8 @@ VITE_TITLE = smilingFace
 
 # 接口地址
 # VITE_API_BASEURL = http://192.168.31.14:9003
-VITE_API_BASEURL = http://192.168.1.245:9003
-VITE_FILEURL = http://192.168.1.245:10005/education/
+VITE_API_BASEURL = http://192.168.207.179:9003
+VITE_FILEURL = http://192.168.207.179:10005/education/
 # VITE_API_BASEURL = http://192.168.31.14:9003
 # VITE_API_BASEURL = http://192.168.31.6:9003
 

+ 11 - 2
src/components/Editor/index.vue

@@ -1,5 +1,8 @@
 <template>
-	<Editor v-model="contentValue" :init="init" :disabled="disabled" :placeholder="placeholder" @onClick="onClick" />
+	<div class="mydiv">
+		<Editor v-model="contentValue" :init="init" :disabled="disabled" :placeholder="placeholder" @onClick="onClick" />
+	</div>
+
 </template>
 
 <script setup name="Editor">
@@ -123,7 +126,7 @@
 		tinymce.init({})
 	})
 </script>
-<style>
+<style scoped>
 	/* 在el-dialog中tinymce z-index 被太小而被遮挡时要加这两句 */
 	.tox-tinymce-aux {
 		z-index: 99999 !important;
@@ -131,4 +134,10 @@
 	.tinymce.ui.FloatPanel {
 		z-index: 99;
 	}
+	.mydiv {
+		:deep(.tox-statusbar__path) {
+			display: none !important;
+		}
+	}
+	/*.tox .tox-statusbar a, .tox */
 </style>

+ 1 - 1
src/utils/request.js

@@ -115,7 +115,7 @@ service.interceptors.response.use(
 			// 统一成功提示
 			const responseUrl = response.config.url
 			const apiNameArray = [
-				'add',
+				// 'add',
 				'edit',
 				'delete',
 				'update',

+ 5 - 4
src/views/forum/form.vue

@@ -20,7 +20,7 @@
 							max
 							allow-clear
 							show-count
-							:maxlength="100"
+							:maxlength="50"
 						/>
 					</a-form-item>
 				</a-col>
@@ -145,17 +145,18 @@
 
 	// 默认要校验的
 	const formRules = {
-		postTitle: [required('请输入标题')],
+		postTitle: [required('请输入标题'),],
 		typeId: [required('请选择分类')],
-		postContent: [required('请输入内容')]
+		postContent: [required('请输入内容'),{ max: 200, message: '不能超过200个字符' }]
 	}
 
 	const categoryOptions = tool.dictList('MENU_TYPE')
 	const visibleOptions = tool.dictList('MENU_VISIBLE')
 	// 验证并提交数据
 	const onSubmit = () => {
-		submitLoading.value = true
+
 		formRef.value.validate().then(() => {
+			submitLoading.value = true
 			if (formData.value.appointUserArr && formData.value.appointUserArr.length > 1) {
 				formData.value.appointUser = formData.value.appointUserArr.join(',')
 			}

+ 11 - 3
src/views/forum/index.vue

@@ -73,9 +73,15 @@
 						<div class="forum-list-content one-line" v-html="record.postContent"></div>
 					</template>
 					<template v-if="column.dataIndex === 'lastReplyUserAvatar'">
-						<a-tooltip :title="record.lastReplyUserNickName" placement="top">
-							<a-avatar :src="record.lastReplyUserAvatar"></a-avatar>
-						</a-tooltip>
+						<div v-if="record.replyCount==0">
+							<span>无人回复</span>
+						</div>
+						<div v-if="record.replyCount>0">
+							<a-tooltip :title="record.lastReplyUserNickName" placement="top">
+								<a-avatar :src="record.lastReplyUserAvatar"></a-avatar>
+							</a-tooltip>
+						</div>
+
 					</template>
 					<template v-if="column.dataIndex === 'lastReplyTime'">
 						<div>{{ formatDateTime(record.lastReplyTime) }}</div>
@@ -93,6 +99,7 @@
 	import Form from './form.vue'
 	import { parseTime } from '@/utils/exam'
 	import { useRoute, useRouter } from 'vue-router'
+	import EventBus from "@/utils/EventBus";
 	const route = useRoute()
 	const router = useRouter()
 	const formRef = ref()
@@ -335,6 +342,7 @@
 		router.push({
 			path: '/'
 		})
+		EventBus.emit('onSetHeader','')
 	}
 	onMounted(() => {
 		getTypeList()

+ 0 - 1
src/views/forum/replyForm.vue

@@ -56,7 +56,6 @@
 
 	// 打开抽屉
 	const onOpen = (record, module, childId, formType) => {
-		console.log("🚀 ~ onOpen ~ record, module, childId, formType:", record, module, childId, formType)
 		moduleId.value = module ?? record.postId
 		replyid.value = childId ?? '-1'
 		visible.value = true

+ 9 - 0
src/views/portal/components/Header.vue

@@ -63,6 +63,7 @@
 	import headerIcon from './headerIcon.vue'
 	import { globalStore } from '@/store'
 	import { Modal, message } from 'ant-design-vue'
+	import EventBus from "@/utils/EventBus";
 	const router = useRouter()
 	const route = useRoute()
 	const current = ref([route.path.slice(1)]) // 默认选中“资源中心”
@@ -135,6 +136,14 @@
 			onCancel() {}
 		})
 	}
+
+	const onSetHeader = (data) => {
+		console.log('收到了呢',data)
+		current.value = data
+	}
+
+	EventBus.off('onSetHeader', onSetHeader)
+	EventBus.on('onSetHeader', onSetHeader)
 </script>
 
 <style scoped lang="less">

+ 11 - 3
src/views/slogin/login.vue

@@ -6,7 +6,7 @@
 					<span style="font-size: 20px">学生登录</span>
 				</div>
 
-				<a-form ref="loginForm" :model="ruleForm" :rules="rules">
+				<a-form ref="loginForm" v-show="activeKey == 'userAccount'" :model="ruleForm" :rules="rules">
 					<a-form-item name="account">
 						<a-input
 							v-model:value="ruleForm.account"
@@ -68,6 +68,7 @@
 					</a-form-item>
 					<div style="color: gray;text-align: center;width: 100%;font-size: 12px;">统一身份认证平台登录(针对学院在籍学员)</div>
 				</a-form>
+				<Restlogin ref="restlogin" v-show="activeKey == 'restPass'"/>
 			</a-card>
 		</div>
 	</div>
@@ -75,6 +76,7 @@
 
 <script>
 	import loginApi from '@/api/auth/loginApi'
+	import Restlogin from './restlogin.vue'
 	import phoneLoginForm from './phoneLoginForm.vue'
 	import threeLogin from './threeLogin.vue'
 	import smCrypto from '@/utils/smCrypto'
@@ -90,7 +92,8 @@
 		name: 'Login',
 		components: {
 			phoneLoginForm,
-			threeLogin
+			threeLogin,
+			Restlogin
 		},
 		data() {
 			return {
@@ -194,7 +197,12 @@
 					// 获取token
 					try {
 						const loginToken = await loginApi.login(loginData)
-						afterLogin(loginToken)
+						afterLogin(loginToken,()=>{
+							this.activeKey = 'restPass'
+							this.$nextTick(() => {
+								this.$refs.restlogin.setData(loginToken)
+							})
+						})
 					} catch (err) {
 						this.loading = false
 						this.loginCaptcha()

+ 210 - 0
src/views/slogin/restlogin.vue

@@ -0,0 +1,210 @@
+<template>
+	<div >
+		<a-form ref="loginForm" :model="ruleForm" :rules="rules">
+<!--			<a-form-item name="account">-->
+<!--				<a-input-->
+<!--					v-model:value="ruleForm.account"-->
+<!--					:placeholder="$t('login.accountPlaceholder')"-->
+<!--					size="large"-->
+<!--					@keyup.enter="login"-->
+<!--				>-->
+<!--					<template #prefix>-->
+<!--						<UserOutlined class="login-icon-gray" />-->
+<!--					</template>-->
+<!--				</a-input>-->
+<!--			</a-form-item>-->
+			<span style="margin-bottom: 20px;  color: red">密码已过期请输入新密码</span>
+			<a-form-item name="password">
+				<a-input-password
+					v-model:value="ruleForm.password"
+					placeholder="请输入新密码"
+					size="large"
+					autocomplete="off"
+					@keyup.enter="login"
+				>
+					<template #prefix>
+						<LockOutlined class="login-icon-gray" />
+					</template>
+				</a-input-password>
+			</a-form-item>
+			<a-form-item name="newPassword">
+				<a-input-password
+					v-model:value="ruleForm.newPassword"
+					placeholder="请再次输入新密码"
+					size="large"
+					autocomplete="off"
+					@keyup.enter="login"
+				>
+					<template #prefix>
+						<LockOutlined class="login-icon-gray" />
+					</template>
+				</a-input-password>
+			</a-form-item>
+
+
+			<a-form-item>
+				<a-button type="primary" class="w-full" :loading="loading" round size="large" @click="login"
+				>{{ $t('login.signIn') }}
+				</a-button>
+			</a-form-item>
+		</a-form>
+	</div>
+</template>
+
+<script>
+	import loginApi from '@/api/auth/loginApi'
+	import phoneLoginForm from './phoneLoginForm.vue'
+	import threeLogin from './threeLogin.vue'
+	import smCrypto from '@/utils/smCrypto'
+	import { required } from '@/utils/formRules'
+	import { afterLogin } from './util'
+	import config from '@/config'
+	import configApi from '@/api/dev/configApi'
+	import tool from '@/utils/tool'
+	import { globalStore, iframeStore, keepAliveStore, viewTagsStore } from '@/store'
+	import { mapActions, mapState } from 'pinia'
+	import {message} from "ant-design-vue";
+	import userCenterApi from '@/api/sys/userCenterApi'
+
+	export default {
+		name: 'Login',
+		components: {
+			phoneLoginForm,
+			threeLogin
+		},
+		data() {
+			return {
+				token : '',
+				activeKey: 'userAccount',
+				captchaOpen: config.SYS_BASE_CONFIG.SNOWY_SYS_DEFAULT_CAPTCHA_OPEN,
+				validCodeBase64: '',
+				ruleForm: {
+					account: '',
+					password: '',
+					newPassword: '',
+					validCode: '',
+					validCodeReqNo: '',
+					autologin: false,
+					eduIdentity: '0'
+				},
+				rules: {
+					// account: [required(this.$t('login.accountError'), 'blur')],
+					password: [required(this.$t('login.PWError'), 'blur')],
+					reestpassword: [required(this.$t('login.PWError'), 'blur')]
+				},
+				loading: false,
+				config: {
+					lang: tool.data.get('APP_LANG') || this.$CONFIG.LANG,
+					theme: tool.data.get('APP_THEME') || 'default'
+				},
+				lang: [
+					{
+						name: '简体中文',
+						value: 'zh-cn'
+					},
+					{
+						name: 'English',
+						value: 'en'
+					}
+				]
+			}
+		},
+		computed: {
+			...mapState(globalStore, ['sysBaseConfig']),
+		},
+		watch: {
+			'config.theme': function (val) {
+				document.body.setAttribute('data-theme', val)
+			},
+			'config.lang': function (val) {
+				this.$i18n.locale = val
+				tool.data.set('APP_LANG', val)
+			}
+		},
+		created() {
+			this.clearViewTags()
+			this.clearKeepLive()
+			this.clearIframeList()
+		},
+		mounted() {
+			let formData = ref(config.SYS_BASE_CONFIG)
+			configApi.configSysBaseList().then((data) => {
+				if (data) {
+					data.forEach((item) => {
+						formData.value[item.configKey] = item.configValue
+					})
+					this.captchaOpen = formData.value.SNOWY_SYS_DEFAULT_CAPTCHA_OPEN
+					tool.data.set('SNOWY_SYS_BASE_CONFIG', formData.value)
+					this.setSysBaseConfig(formData.value)
+					this.refreshSwitch()
+				}
+			})
+		},
+		methods: {
+			...mapActions(keepAliveStore, ['clearKeepLive']),
+			...mapActions(viewTagsStore, ['clearViewTags']),
+			...mapActions(iframeStore, ['clearIframeList']),
+			...mapActions(globalStore, ['setSysBaseConfig']),
+			// 通过开关加载内容
+			refreshSwitch() {
+				// 判断是否开启验证码
+				if (this.captchaOpen === 'true') {
+					// 加载验证码
+					this.loginCaptcha()
+					// 加入校验
+					this.rules.validCode = [required(this.$t('login.validError'), 'blur')]
+				}
+			},
+			// 获取验证码
+			loginCaptcha() {
+				loginApi.getPicCaptcha().then((data) => {
+					this.validCodeBase64 = data.validCodeBase64
+					this.ruleForm.validCodeReqNo = data.validCodeReqNo
+				})
+			},
+			// 用户名密码登录
+			async login() {
+				this.$refs.loginForm.validate().then(async () => {
+					this.loading = true
+					const loginData = {
+						// account: this.ruleForm.account,
+						// 密码进行SM2加密,传输过程中看到的只有密文,后端存储使用hash
+						password: this.ruleForm.password,
+						newPassword: this.ruleForm.newPassword,
+						// validCode: this.ruleForm.validCode,
+						// validCodeReqNo: this.ruleForm.validCodeReqNo,
+						// eduIdentity: this.ruleForm.eduIdentity
+					}
+					if(loginData.password != loginData.newPassword){
+						message.error('两个密码不一致');
+						return
+					}
+					tool.data.set('TOKEN', this.token)
+					tool.cookie.set('Token', this.token)
+					let res = await userCenterApi.userUpdatePassword(loginData)
+					console.log('修改你密码',res)
+					afterLogin(this.token)
+					this.loading = false
+					// // 获取token
+					// try {
+					// 	const loginToken = await loginApi.login(loginData)
+					// 	afterLogin(loginToken)
+					// } catch (err) {
+					// 	this.loading = false
+					// 	this.loginCaptcha()
+					// }
+				})
+			},
+			configLang(key) {
+				this.config.lang = key
+			},
+			setData(token){
+				this.token = token
+			}
+		}
+	}
+</script>
+
+<style lang="less">
+	@import 'login';
+</style>

+ 45 - 35
src/views/slogin/util.js

@@ -7,7 +7,7 @@ import { message } from 'ant-design-vue'
 import { useGlobalStore, useMyResourceStore } from '@/store'
 import routerUtil from '@/utils/routerUtil'
 
-export const afterLogin = async (loginToken) => {
+export const afterLogin = async (loginToken,callBack) => {
 	tool.data.set('TOKEN', loginToken)
 	//cookie里添加 token
 	tool.cookie.set('Token', loginToken)
@@ -15,43 +15,53 @@ export const afterLogin = async (loginToken) => {
 	const loginUser = await loginApi.getLoginUser()
 	const globalStore = useGlobalStore()
 	const myResourceStore = useMyResourceStore()
-	globalStore.setUserInfo(loginUser)
-	myResourceStore.getUserInfo()
-	tool.data.set('USER_INFO', loginUser)
 
-	// 获取用户的菜单
-	const menu = await userCenterApi.userLoginMenu()
-	let indexMenu = routerUtil.getIndexMenu(menu).path
-	tool.data.set('MENU', menu)
-	// 重置系统默认应用
-	tool.data.set('SNOWY_MENU_MODULE_ID', menu[0].id)
-	message.success('登录成功')
-	if (!!tool.data.get('LAST_VIEWS_PATH')) {
-		// 如果有缓存,将其登录跳转到最后访问的路由
-		indexMenu = tool.data.get('LAST_VIEWS_PATH')
-	}
-	// 如果存在退出后换新账号登录,进行重新匹配,匹配无果则默认首页
-	if (menu) {
-		let routerTag = 0
-		menu.forEach((item) => {
-			if (item.children) {
-				if (JSON.stringify(item.children).indexOf(indexMenu) > -1) {
-					routerTag++
+	if(loginUser.expired == 1 && callBack){
+		tool.data.remove('TOKEN', loginToken)
+		tool.cookie.remove('Token', loginToken)
+		message.error('密码已过期')
+		callBack()
+	}else {
+		globalStore.setUserInfo(loginUser)
+		myResourceStore.getUserInfo()
+		tool.data.set('USER_INFO', loginUser)
+
+		// 获取用户的菜单
+		const menu = await userCenterApi.userLoginMenu()
+		let indexMenu = routerUtil.getIndexMenu(menu).path
+		tool.data.set('MENU', menu)
+		// 重置系统默认应用
+		tool.data.set('SNOWY_MENU_MODULE_ID', menu[0].id)
+		message.success('登录成功')
+		if (!!tool.data.get('LAST_VIEWS_PATH')) {
+			// 如果有缓存,将其登录跳转到最后访问的路由
+			indexMenu = tool.data.get('LAST_VIEWS_PATH')
+		}
+		// 如果存在退出后换新账号登录,进行重新匹配,匹配无果则默认首页
+		if (menu) {
+			let routerTag = 0
+			menu.forEach((item) => {
+				if (item.children) {
+					if (JSON.stringify(item.children).indexOf(indexMenu) > -1) {
+						routerTag++
+					}
 				}
+			})
+			if (routerTag === 0) {
+				// 取首页
+				indexMenu = routerUtil.getIndexMenu(menu).path
 			}
-		})
-		if (routerTag === 0) {
-			// 取首页
-			indexMenu = routerUtil.getIndexMenu(menu).path
 		}
-	}
-	dictApi.dictTree().then((data) => {
-		// 设置字典到store中
-		tool.data.set('DICT_TYPE_TREE_DATA', data)
-	})
-	setTimeout(() => {
-		router.replace({
-			path: '/'
+		dictApi.dictTree().then((data) => {
+			// 设置字典到store中
+			tool.data.set('DICT_TYPE_TREE_DATA', data)
 		})
-	}, 100)
+		setTimeout(() => {
+			router.replace({
+				path: '/'
+			})
+		}, 100)
+	}
+
+
 }

+ 7 - 0
src/views/student/classCentre/index.vue

@@ -147,6 +147,7 @@
 	import handouts from './handouts.vue'
 	import subtitleBox from './subtitle.vue'
 	import Broadcast from '@/utils/Broadcast.js'
+	import {message} from "ant-design-vue";
 
 	const route = useRoute()
 	const router = useRouter()
@@ -385,6 +386,7 @@
 		}
 	}
 	const isLike = () => {
+		console.log('收藏状态',classDetail.value.isCollect)
 		classCentre
 			.classCollectAdd(
 				{
@@ -393,6 +395,11 @@
 				classDetail.value.isCollect
 			)
 			.then(() => {
+				if(classDetail.value.isCollect == false){
+					message.success('添加收藏')
+				}else{
+					message.warn('取消收藏')
+				}
 				classCentre.courseDetail({ courseId: route.query.id }).then((data) => {
 					classDetail.value = data
 				})

+ 4 - 4
src/views/student/paper/index.vue

@@ -107,8 +107,8 @@
 	})
 	const typeOptionsVal = ref([
 		{
-			label: '考试',
-			title: '任务',
+			label: '普通考试',
+			title: '普通考试',
 			value: '1',
 			paperType: '6'
 		},
@@ -126,8 +126,8 @@
 			paperType: '5'
 		},
 		{
-			label: '作业',
-			title: '作业',
+			label: '课时作业',
+			title: '课时作业',
 			value: '4',
 			paperType: '2',
 			funcType: '4'