Pārlūkot izejas kodu

Merge branch 'liqk/develop' into develop

1755507413 2 gadi atpakaļ
vecāks
revīzija
37d05edd65

+ 12 - 0
TEAMModelOS/ClientApp/src/api/areaArt.js

@@ -6,4 +6,16 @@ export default {
     findArtSetting: function (data) {
         return post('/area/art-setting/find-id', data)
     },
+    findArtPaperList: function (data) {
+        return post('/area/art-setting/find-art-papers', data)
+    },
+    saveArt: function (data) {
+        return post('/common/art/save', data)
+    },
+    findArtList: function (data) {
+        return post('/common/art/find', data)
+    },
+    findArtSummary: function (data) {
+        return post('/common/art/find-summary', data)
+    },
 }

+ 24 - 0
TEAMModelOS/ClientApp/src/common/BaseLayout.vue

@@ -597,6 +597,30 @@ export default {
             isShow: this.$store.state.config.srvAdr == 'China' && this.$store.state.userInfo.hasSchool
           }]
         },
+        //艺术评测
+        {
+          icon: 'iconfont icon-yishu',
+          name: this.$t('area.base.artData'),
+          router: '',
+          tag: '',
+          role: 'admin',
+          permission: '',
+          subName: 'artExam',
+          menuName: 'artExam',
+          child: [
+            {
+              icon: 'iconfont icon-test',
+              name: '评测活动',
+              router: '/home/mgtArtExam',
+              tag: '',
+              role: 'admin',
+              permission: '',
+              menuName: 'mgtArtExam',
+              isShow: this.$store.state.config.srvAdrType === 'test'
+            },
+          ],
+          isShow: this.$store.state.config.srvAdrType === 'test'
+        },
         // 学情分析
         {
           icon: 'iconfont icon-xueqing',

+ 20 - 0
TEAMModelOS/ClientApp/src/router/routes.js

@@ -1330,6 +1330,26 @@ export const routes = [{
             activeName: 'auth',
             middleware: ['login', 'ability:admin,auth-read|auth-upd'],
         }
+    },
+    //管理艺术评测
+    {
+        path: 'mgtArtExam',
+        name: 'mgtArtExam',
+        component: resolve => require(['@/view/artexam/Mgt.vue'], resolve),
+        meta: {
+            activeName: 'artExam',
+            middleware: ['login', 'ability:admin'],
+        }
+    },
+    //创建艺术评测
+    {
+        path: 'createArtExam',
+        name: 'createArtExam',
+        component: resolve => require(['@/view/artexam/Create.vue'], resolve),
+        meta: {
+            activeName: 'artExam',
+            middleware: ['login', 'ability:admin'],
+        }
     }
     ]
 },

+ 835 - 0
TEAMModelOS/ClientApp/src/view/artexam/Create.vue

@@ -0,0 +1,835 @@
+<template>
+	<div class="create-art-container">
+		<vuescroll>
+			<div class="create-form-wrap">
+				<!-- 上一步 -->
+				<div
+					v-show="step > 0"
+					class="step-handler last-step"
+					@click="lastStep()"
+				>
+					<span class="step-icon-wrap">
+						<Icon type="ios-arrow-back" size="24" color="white" />
+					</span>
+					<p style="margin-top: 2px">
+						{{ $t("train.create.lastStep") }}
+					</p>
+				</div>
+				<!-- 下一步 -->
+				<div
+					v-show="step < 3"
+					class="step-handler next-step"
+					@click="nextStep()"
+				>
+					<span class="step-icon-wrap">
+						<Icon
+							type="ios-arrow-forward"
+							size="24"
+							color="white"
+						/>
+					</span>
+					<p style="margin-top: 2px">
+						{{ $t("train.create.nextStep") }}
+					</p>
+				</div>
+				<Steps :current="step" class="step-wrap">
+					<Step
+						:title="$t('train.create.baseInfo')"
+						@click.native="step = 0"
+					></Step>
+					<!-- <Step :title="$t('train.create.detailInfo')"></Step> -->
+					<Step :title="$t('train.create.advancedTitle')"></Step>
+					<Step :title="$t('train.create.publishTitle')"></Step>
+				</Steps>
+				<!-- 基础设置 -->
+				<Form
+					ref="baseInfo"
+					:model="artInfo"
+					:rules="baseRule"
+					:label-width="100"
+					class="art-form"
+					label-colon
+					v-show="step == 0"
+				>
+					<h1>{{ $t("train.create.baseInfo") }}</h1>
+					<FormItem label="名称" prop="name" style="margin-top: 80px">
+						<Input
+							v-special-char
+							v-model="artInfo.name"
+							placeholder="请输入艺术评测活动名称"
+						></Input>
+					</FormItem>
+					<FormItem
+						label="班级"
+						prop="targets"
+						style="margin-top: 30px"
+					>
+						<el-cascader
+							ref="evtarget"
+							size="small"
+							:show-all-levels="false"
+							clearable
+							:options="csOptions"
+							:props="props"
+							@change="treeChange"
+							style="width: 100%"
+						>
+						</el-cascader>
+					</FormItem>
+				</Form>
+				<!-- 高级设置 -->
+				<Form
+					ref="seniorInfo"
+					:model="artInfo"
+					:rules="trainRule"
+					:label-width="100"
+					class="art-form"
+					label-colon
+					v-show="step == 1"
+				>
+					<h1>{{ $t("train.create.advancedTitle") }}</h1>
+					<!-- 一级指标 -->
+					<CheckboxGroup
+						v-model="artInfo.setting"
+						@on-change="initStatus"
+					>
+						<Checkbox
+							v-for="item in quotas"
+							:key="item.id"
+							:label="item.id"
+							class="check-item"
+						>
+							<span>{{ item.name }}</span>
+						</Checkbox>
+					</CheckboxGroup>
+					<Tabs v-model="tabName">
+						<TabPane
+							v-for="(item, index) in tabListShow"
+							:key="index"
+							:label="item.label"
+							:name="item.name"
+						>
+							<QuoTree
+								:quoid="item.name"
+								:treeData="item.children"
+								@on-check-change="handleCheckChange"
+								@on-setting-change="handleSettingChange"
+								@on-type-change="handleTypeChange"
+							></QuoTree>
+						</TabPane>
+					</Tabs>
+				</Form>
+				<!-- 发布活动 -->
+				<Form
+					class="art-form"
+					label-colon
+					v-show="step == 2  && !published"
+					label-position="left"
+				>
+					<h1>{{ $t("train.create.publishTitle") }}</h1>
+					<FormItem label="名称" style="margin-top: 80px">
+						<span>{{ artInfo.name }}</span>
+					</FormItem>
+					<FormItem label="班级">
+						<span>{{ classNames.join(", ") }}</span>
+					</FormItem>
+					<FormItem label="评价指标">
+						<span>{{ settingNames.join(", ") }}</span>
+					</FormItem>
+					<Button
+						type="primary"
+						class="save-btn"
+						:loading="saveLoading"
+						style="
+							margin: auto;
+							margin-top: 20px;
+							width: 240px;
+							display: block;
+						"
+						@click="publish"
+					>
+						{{ $t("train.create.publishBtn") }}
+					</Button>
+				</Form>
+                <!-- 发布成功 -->
+                <div v-show="step == 2  && published">
+                    <Icon type="md-checkmark-circle-outline" class="published-icon" />
+                    <p class="success-text">
+                        {{$t('train.create.publishOk')}}
+                    </p>
+                    <p class="link-text" @click="toArtMgt">
+                        {{$t('train.create.viewInfo')}}
+                    </p>
+                </div>
+			</div>
+		</vuescroll>
+	</div>
+</template>
+
+<script>
+import QuoTree from "./QuoTree.vue"
+import BlobTool from "@/utils/blobTool.js"
+import { mapGetters } from "vuex"
+export default {
+	components: {
+		QuoTree
+	},
+	data() {
+		return {
+            published:false,
+			saveLoading: false,
+			tabListShow: [],
+			tabList: [],
+			tabName: "",
+			props: {
+				multiple: true,
+				value: "id",
+				label: "name"
+			},
+			step: 0,
+			artInfo: {
+				name: "",
+				targets: [],
+				setting: []
+			},
+			settingDetail: {},
+			baseRule: {
+				name: [
+					{
+						required: true,
+						message: "请输入艺术评测活动名称",
+						trigger: "change"
+					}
+				],
+				targets: [
+					{
+						required: true,
+						type: "array",
+						message: this.$t("train.create.targetErr"),
+						trigger: "blur"
+					}
+				]
+			},
+			// 学业指标相关设置
+			studySetting: {
+				hasKn: false,
+				hasSkill: false,
+				baseKn: {},
+				baseSkill: {}
+			},
+			trainRule: {},
+			allList: [],
+			quotas: []
+		}
+	},
+	computed: {
+		...mapGetters({
+			curPeriod: "user/getCurPeriod"
+		}),
+		//级联选择年级班级
+		csOptions() {
+			let data = []
+			//填充行政班数据
+			if (this.curPeriod.id) {
+				//计算学级逻辑
+				let date = new Date()
+				let curYear = date.getFullYear()
+				let month = date.getMonth() + 1
+				let start = this.curPeriod.semesters.find((item) => {
+					return item.start == 1
+				})
+				// 根据入学月份确定当前年级和学级的关系
+				if (start && month < start.month) {
+					curYear--
+				}
+				this.curGrades.forEach((item, index) => {
+					let dataItem = {
+						id: index, //年级使用index
+						name: `${item}(${curYear - index}${this.$t(
+							"unit.gradeYear"
+						)})`,
+						year: curYear - index,
+						children: []
+					}
+					let child = this.allList.filter((classItem) => {
+						return (
+							classItem.year == curYear - index &&
+							classItem.type == "class"
+						)
+					})
+					dataItem.children = child.length ? child : undefined
+					if (child.length) data.push(dataItem)
+				})
+			}
+			return data
+		},
+		//计算当前学段下面的年级信息
+		curGrades() {
+			if (this.curPeriod.grades) {
+				return this.curPeriod.grades
+			} else {
+				return []
+			}
+		},
+		classNames() {
+			let names = this.artInfo.targets.map((item) => {
+				let c = this.allList.find((c) => c.id === item)
+				return c.name
+			})
+			return names
+		},
+		settingNames() {
+			let settingMap = {}
+            this.quotas.forEach((item) => {
+				settingMap[item.id] = item.name
+			})
+			let names = this.artInfo.setting.map((item) => {
+				return settingMap[item]
+			})
+			return names
+		}
+	},
+	watch: {
+		"$store.state.user.curPeriod": {
+			deep: true,
+			immediate: true,
+			handler(n, o) {
+				if (n) {
+					this.getTargetList()
+				}
+			}
+		}
+	},
+	methods: {
+        toArtMgt(){
+            this.$router.push({
+                name:'mgtArtExam'
+            })
+        },
+		handleCheckChange(data) {
+			if (!this.settingDetail[data.quoid])
+				this.settingDetail[data.quoid] = {}
+			this.settingDetail[data.quoid]["checked"] = data.data
+		},
+		handleTypeChange(data) {
+			if (!this.settingDetail[data.quoid])
+				this.settingDetail[data.quoid] = {}
+			this.settingDetail[data.quoid]["type"] = data.data
+		},
+		handleSettingChange(data) {
+			if (!this.settingDetail[data.quoid])
+				this.settingDetail[data.quoid] = {}
+			this.settingDetail[data.quoid]["setting"] = data.data
+		},
+		/* 获取当前区级设置数据 */
+		getAreaSetting() {
+			this.$api.areaArt
+				.findArtSetting({
+					areaId: sessionStorage.getItem("areaId")
+				})
+				.then((res) => {
+					if (res.setting) {
+						console.log(res)
+						// this.artDimensions = res.setting.dimensions
+						this.quotas = res.setting.quotas
+						this.tabList = this.quotas.map((q) => {
+							return {
+								name: q.id,
+								label: q.name,
+								children: q.children
+							}
+						})
+					} else {
+						this.artDimensions = []
+					}
+				})
+		},
+		async formatData() {
+			return new Promise(async (r, j) => {
+				try {
+					let baseKeys = Object.keys(this.settingDetail)
+					let settings = []
+					for (const key of baseKeys) {
+						let curSet = this.settingDetail[key]
+						if (!curSet.checked?.checkedKeys) continue
+						let lastIds = curSet.checked.checkedKeys.filter(
+							(item) => {
+								let isLast = curSet.checked.checkedNodes.find(
+									(n) => n.id === item && !n.children.length
+								)
+								return !!isLast
+							}
+						)
+						console.log("laseId", lastIds)
+						for (const id of lastIds) {
+							let s = {
+								id,
+								task: []
+							}
+							let type = curSet.type[id]
+							if (type == "score") {
+								s.task.push({ type })
+							} else if (type == "exam") {
+								let quoSetting = curSet.setting[id]
+								let examRes = await this.toSaveExamInfo(
+									quoSetting
+								)
+								examRes.forEach((res, index) => {
+									s.task.push({
+										type,
+										acId: res.exam.id,
+										subject: res.exam.subjects[0].id,
+										unorder:
+											quoSetting.settings[index].unorder
+									})
+								})
+							} else if (type == "work") {
+								let quoSetting = curSet.setting[id]
+								quoSetting.settings.forEach((w) => {
+									s.task.push({
+										type,
+										workDesc: w.desc,
+										workEnd: w.endTime,
+										subject: w.subject
+									})
+								})
+							}
+							settings.push(s)
+						}
+					}
+					console.log("所有设置", settings)
+					r(settings)
+				} catch (e) {
+					j(e)
+				}
+			})
+		},
+		async publish() {
+			console.log(this.settingDetail)
+			try {
+				let settings = await this.formatData()
+				let params = {
+					name: this.artInfo.name,
+					target: this.artInfo.targets,
+					owner: "school",
+					scope: "school",
+					school: this.$store.state.userInfo.schoolCode,
+					classes: this.artInfo.targets,
+					settings: settings
+				}
+				this.$api.areaArt
+					.saveArt({
+						art: params
+					})
+					.then(
+						(res) => {
+							this.$Message.success("艺术评测发布成功")
+                            this.published = true
+						},
+						(err) => {
+							this.$Message.error("艺术评测发布失败")
+						}
+					)
+			} catch (e) {
+				console.error(e)
+			}
+		},
+		// 保存评测相关数据
+		async toSaveExamInfo(quoSetting) {
+			return new Promise(async (r, j) => {
+				let baseKn = quoSetting
+				let promises = []
+				let resourcePaper = []
+				for (const setting of baseKn.settings) {
+					let apiPapers = await this.getPaperInfo(setting.paper)
+					resourcePaper.push(setting.paper)
+					let requestData = {
+						id: this.$jsFn.uuid(),
+						code: this.$store.state.userInfo.schoolCode,
+						school: this.$store.state.userInfo.schoolCode,
+						name: `${this.artInfo.name}-${setting.subject}`,
+						creatorId: this.$store.state.userInfo.TEAMModelId,
+						// type: this.evaluationInfo.type,
+						period: {
+							id: this.curPeriod.id,
+							name: this.curPeriod.name
+						},
+						grades: [],
+						subjects: [
+							{
+								id: setting.subject,
+								name:
+									setting.subject == "music" ? "音乐" : "美术"
+							}
+						],
+						papers: [apiPapers],
+						// examType: this.evaluationInfo.examType,
+						year: new Date().getFullYear(),
+						// range: this.mode,
+						source: "0",
+						classes: this.artInfo.targets,
+						stuLists: [],
+						targets: [],
+						startTime: setting.startTime || -1, //立即发布由后端获取时间
+						endTime: setting.endTime,
+						scope: "school",
+						createTime: Math.round(new Date()),
+						owner: "school" //后面新增字段
+						// income: this.evaluationInfo.income,
+						// touch: this.evaluationInfo.touch
+					}
+					promises.push(
+						this.$api.learnActivity.SaveExamInfo(requestData)
+					)
+				}
+				Promise.all(promises).then(
+					async (reses) => {
+						console.log("评测保存成功", reses)
+						// 评测保存成功还需要复制试卷
+						let schoolSas = {
+							sas:
+								"?" +
+								this.$store.state.user.schoolProfile.blob_sas,
+							url: this.$store.state.user.schoolProfile.blob_uri.slice(
+								0,
+								this.$store.state.user.schoolProfile.blob_uri.lastIndexOf(
+									this.$store.state.userInfo.schoolCode
+								) - 1
+							),
+							name: this.$store.state.userInfo.schoolCode
+						}
+						let schoolBlob = new BlobTool(
+							schoolSas.url,
+							schoolSas.name,
+							schoolSas.sas,
+							"school"
+						)
+						let paperSas = await this.$tools.getBlobSas("hbcn")
+						let paperBlob = new BlobTool(
+							paperSas.url,
+							paperSas.name,
+							"?" + paperSas.sas,
+							"school"
+						)
+						reses.forEach((res, index) => {
+							let targetFolder = "exam/" + res.exam.id + "/paper/"
+							//这里评测都是单科处理
+							schoolBlob
+								.copyFolder(
+									targetFolder +
+										res.exam.subjects[0].id +
+										"/",
+									resourcePaper[index].blob.substring(1),
+									paperBlob
+								)
+								.then(
+									(res) => {
+									},
+									(err) => {
+										this.$Message.error("试卷复制失败")
+									}
+								)
+						})
+						r(reses)
+					},
+					(err) => {
+						console.error("评测保存失败")
+						j(err)
+					}
+				)
+			})
+		},
+		//拼接API需要的paper数据
+		getPaperInfo(simplePaper) {
+			return new Promise(async (r, j) => {
+				try {
+					simplePaper.scope = "school"
+					let fullPaper = await this.$evTools.getFullPaper(
+						simplePaper
+					)
+					if (fullPaper) {
+						let apiPaper = {}
+						apiPaper.id = fullPaper.id
+						apiPaper.code = fullPaper.code
+						apiPaper.name = fullPaper.name
+						apiPaper.blob = simplePaper.blob
+						apiPaper.scope = fullPaper.scope
+						apiPaper.sheet = fullPaper.sheet //答题卡 //202108021讨论: 创建评测不需要传答题卡id,由更新答题卡id去做关联。
+						apiPaper.multipleRule = fullPaper.multipleRule
+						apiPaper.answers = []
+						apiPaper.point = []
+						apiPaper.knowledge = []
+						apiPaper.field = []
+						apiPaper.time = fullPaper.time
+						apiPaper.type = [] //后面新增字段, 保存每个题目类型
+						for (let k = 0; k < fullPaper.slides.length; k++) {
+							if (fullPaper.slides[k].type !== "compose") {
+								apiPaper.answers.push(
+									fullPaper.slides[k].scoring.ans
+										? fullPaper.slides[k].scoring.ans
+										: []
+								)
+								apiPaper.point.push(
+									fullPaper.slides[k].scoring.score
+								)
+								apiPaper.knowledge.push(
+									fullPaper.slides[k].scoring.knowledge
+										? fullPaper.slides[k].scoring.knowledge
+										: []
+								)
+								apiPaper.field.push(
+									fullPaper.slides[k].scoring.field
+										? fullPaper.slides[k].scoring.field
+										: []
+								)
+								apiPaper.type.push(fullPaper.slides[k].type) //后面新增字段, 保存每个题目类型
+							}
+						}
+						r(apiPaper)
+					} else {
+						j("paperErr")
+					}
+				} catch (e) {
+					j("paperErr")
+				}
+			})
+		},
+		//保存学业指标作业相关数据
+		toSaveWorkInfo() {},
+		handleSetKn(data) {
+			this.studySetting.baseKn = this._.cloneDeep(data)
+			console.log(this.studySetting)
+		},
+		initStatus(data) {
+			this.tabListShow = this.tabList.filter((item) => {
+				return data.includes(item.name)
+			})
+			this.tabName =
+				this.artInfo.setting[data.length - 1] == "sign" &&
+				this.artInfo.setting.length > 1
+					? this.artInfo.setting[data.length - 2]
+					: this.artInfo.setting[data.length - 1]
+		},
+		lastStep() {
+			this.step--
+		},
+		nextStep() {
+			switch (this.step) {
+				case 0:
+					this.checkBaseInfo()
+					break
+				case 1:
+					let isErr = this.checkSettingInfo()
+					if (!isErr) this.step++
+					break
+				default:
+					this.step++
+					break
+			}
+		},
+		checkBaseInfo() {
+			this.$refs["baseInfo"].validate((valid) => {
+				if (valid) {
+					this.step++
+				} else {
+					this.$Message.error(this.$t("train.create.fullInfo"))
+				}
+			})
+		},
+		checkSettingInfo() {
+			let isErr = false
+			let settings = this.artInfo.setting
+			if (!settings.length) {
+				return this.$Message.error("请勾选艺术评价指标")
+			}
+			for (let setting of settings) {
+				switch (setting) {
+					case "study":
+						isErr = this.checkStudyInfo()
+						break
+					default:
+						break
+				}
+			}
+			return isErr
+		},
+		checkStudyInfo() {
+			let isErr = false
+			if (!this.studySetting.hasKn && !this.studySetting.hasSkill) {
+				this.$Message.error("请完成学业指标相关设置")
+				isErr = true
+				return isErr
+			}
+			// 检查基础知识相关设置
+			if (this.studySetting.hasKn) {
+				isErr = this.checkBaseKn()
+			}
+			return isErr
+		},
+		checkBaseKn() {
+			let baseKn = this.studySetting.baseKn
+			console.log(baseKn)
+			let isErr = false
+			if (!baseKn.subjects?.length) {
+				this.$Message.error("请设置基础知识评测科目")
+				isErr = true
+				return isErr
+			}
+			//检查对应学科是否有对应的配置
+			for (const item of baseKn.subjects) {
+				let set = baseKn.settings.find((s) => s.subject === item)
+				if (!set) {
+					this.$Message.error(
+						`请完成基础知识指标${
+							item == "music" ? "音乐" : "美术"
+						}学科的相关设置`
+					)
+					isErr = true
+					break
+				}
+			}
+			if (isErr) return isErr
+			// 检查每个学科的设置是否完整
+			for (const setting of baseKn.settings) {
+				let { startTime, endTime, paper } = setting
+				if (!startTime || !endTime || !paper) {
+					this.$Message.error(
+						`请完成${
+							setting.subject == "music" ? "音乐" : "美术"
+						}学科的相关设置`
+					)
+					isErr = true
+					break
+				}
+			}
+			return isErr
+		},
+		getTargetList() {
+			if (!this.curPeriod?.id) return
+			let params = {
+				tmdid: this.$store.state.userInfo.TEAMModelId,
+				schoolId: this.$store.state.userInfo.schoolCode,
+				periodId: this.curPeriod.id,
+				opt: "manage"
+			}
+			this.$api.common.getActivityTarget(params).then(
+				(res) => {
+					this.allList = res.groupLists
+				},
+				(err) => {
+					this.$Messag.error("查询发布对象失败")
+				}
+			)
+		},
+		treeChange(data) {
+			console.log(data)
+			this.artInfo.targets = data.map((item) => item[1])
+		}
+	},
+	created() {
+		this.getAreaSetting()
+	}
+}
+</script>
+
+<style lang="less" scoped>
+.link-text{
+    text-align: center;
+    text-decoration: underline;
+    font-weight: 400;
+    font-size: 14px;
+    color: #909090;
+    margin-top: 30px;
+    cursor: pointer;
+}
+.success-text{
+    text-align: center;
+    margin-top: 10px;
+    color: #19be6b;
+    font-size: 20px;
+    font-weight: 600;
+}
+.published-icon{
+    color: #19be6b;
+    font-size: 99px;
+    display: block;
+    margin-top: 150px;
+}
+.subject-name {
+	margin-right: 15px;
+	font-weight: 800;
+}
+.content-block {
+	background: #f0f0f0;
+	padding: 20px 10px;
+	border-radius: 4px;
+	margin-bottom: 20px;
+	margin-top: 10px;
+}
+.check-item {
+	user-select: none;
+	display: block;
+	margin-bottom: 20px;
+}
+.art-form {
+	width: 800px;
+	margin: auto;
+}
+.create-art-container {
+	width: 100%;
+	height: 100%;
+	padding: 10px;
+}
+.create-form-wrap {
+	background: white;
+	width: 90%;
+	min-height: 800px;
+	margin: auto;
+	margin-top: 10px;
+	padding: 20px;
+	box-shadow: 0px 0px 10px #ccc;
+	border-radius: 5px;
+	position: relative;
+	h1 {
+		font-size: 22px;
+		text-align: center;
+		margin-top: 50px;
+		margin-bottom: 10px;
+	}
+}
+.step-handler {
+	position: absolute;
+	z-index: 999;
+	cursor: pointer;
+	text-align: center;
+	padding: 5px 10px;
+	box-shadow: 0px 0px 3px rgba(0, 0, 0, 0.2);
+	border-radius: 5px;
+	color: #1cc0f3;
+	font-size: 12px;
+	&:hover {
+		background: #f0f0f0;
+	}
+}
+.step-icon-wrap {
+	background: #1cc0f3;
+	color: white;
+	border-radius: 50%;
+	box-shadow: 0px 0px 3px rgba(0, 0, 0, 0.2);
+	display: inline-block;
+}
+.last-step {
+	left: 40px;
+	top: 350px;
+	.step-icon-wrap {
+		padding: 6px 7px 6px 5px;
+	}
+}
+.next-step {
+	right: 40px;
+	top: 350px;
+	.step-icon-wrap {
+		padding: 6px 5px 6px 7px;
+	}
+}
+</style>

+ 307 - 0
TEAMModelOS/ClientApp/src/view/artexam/ExamSetting.vue

@@ -0,0 +1,307 @@
+<template>
+	<div class="subject-content">
+		<!-- 评测试卷 -->
+		<div class="attr-item">
+			<span>评测试卷:</span>
+			<Tag v-if="subjectSetting.paper" color="blue">
+				{{ subjectSetting.paper.name }}
+			</Tag>
+			<span class="choose-paper" @click="selectPaper()">
+				{{ subjectSetting.paper ? "重选" : "请挑选评测试卷" }}
+			</span>
+		</div>
+		<!-- 作答方式 -->
+		<div class="attr-item">
+			<span>作答方式:</span>
+            <RadioGroup v-model="subjectSetting.unorder">
+                <Radio :label="0">
+                    <span>默认排序</span>
+                </Radio>
+                <Radio :label="1">
+                    <span>乱序作答</span>
+                </Radio>
+            </RadioGroup>
+		</div>
+		<!-- 评测时间 -->
+		<div class="attr-item">
+			<span>评测时间:</span>
+			<DatePicker
+                transfer
+				type="datetimerange"
+				placement="bottom-start"
+				placeholder="请设置评测时间"
+                @on-change="handleSetTime"
+                style="width:400px"
+			></DatePicker>
+		</div>
+        <!-- 挑选试卷 -->
+        <Modal
+            v-model="sltPaperStatus"
+            title="挑选艺术评测试卷"
+            :width="1000"
+            footer-hide>
+            <template v-if="!isPreview">
+                <p v-if="$store.state.userInfo.schoolCode != 'hbcn'">
+                    <span style="vertical-align: bottom;" >
+                        试卷来源:
+                    </span>
+                    <RadioGroup v-model="paperResource">
+                        <Radio label="hbcn">
+                            醍摩豆
+                        </Radio>
+                        <Radio :label="$store.state.userInfo.schoolCode">
+                            本校
+                        </Radio>
+                    </RadioGroup>
+                </p>
+                <div class="papaer-list-wrap">
+                    <vuescroll>
+                        <div class="paper-item" v-for="(item,index) in paperListShow" :key="index">
+                            <div class="paper-item-name">
+                                <span>{{(index + 1) + '.  ' + item.name}}</span>
+                            </div>
+                            <div class="paper-item-info">
+                                <span class="info-item">
+                                    {{$t('learnActivity.manual.fitSubject')}}
+                                    <span class="info-bold">{{item.subjectName}}</span>
+                                </span>
+                                <span class="info-item">
+                                    {{$t('learnActivity.manual.quCount')}}
+                                    <span class="info-bold">{{ item.count }}</span>
+                                </span>
+                                <span class="info-item">
+                                    <Icon type="md-time" style="margin-right:8px" size="14" />
+                                    <span class="info-bold">{{$jsFn.dateFormat(item.createTime)}}</span>
+                                </span>
+                                <span class="info-item">{{$t('evaluation.paperList.sortType')}}:
+                                    <span class="info-bold">
+                                        {{ item.itemSort === 1 ? $t('evaluation.paperList.sortByOrder') : $t('evaluation.paperList.sortByType') }}
+                                    </span>
+                                </span>
+                            </div>
+                            <span v-if="item.id == selectedId" style="margin-left:20px;display:block;" class="paper-item-tools">
+                                <Icon custom="iconfont icon-choose" style="margin-right:5px;" :title="$t('learnActivity.manual.stdPaper')" />
+                            </span>
+                            <div v-else class="paper-item-tools">
+                                <span @click.stop="choosePaper(index)">
+                                    <Icon custom="iconfont icon-choose" style="margin-right:5px;" />
+                                    {{$t('learnActivity.manual.stPaper')}}
+                                </span>
+                                <span @click.stop="previewTestPaper(index)" style="margin-left:20px;">
+                                    <Icon type="md-eye" style="margin-right:5px;" />
+                                    {{$t('learnActivity.manual.previewPaper')}}
+                                </span>
+                            </div>
+                        </div>
+                        <EmptyData v-show="!paperListShow.length"></EmptyData>
+                    </vuescroll>
+                </div>
+            </template>
+            <template v-else>
+                <p class="back-to-list" @click="isPreview = false"><Icon type="md-arrow-back" />返回试卷列表</p>
+                <TestPaper :paper="previewPaper" isExamPaper hideSheet></TestPaper>
+            </template>
+        </Modal>
+	</div>
+</template>
+
+<script>
+import TestPaper from '@/view/evaluation/index/TestPaper.vue'
+export default {
+     components: {
+        TestPaper
+    },
+    props:{
+        subject:{
+            type:String,
+            default:'',
+            required:true
+        }
+    },
+	data() {
+		return {
+            subjectSetting:{
+                paper:undefined,
+                unorder:0,
+                startTime:0,
+                endTime:0
+            },
+            isPreview:false,
+            sltPaperStatus:false,
+            paperResource:'hbcn',
+            previewPaper:undefined,
+            selectedId:'',
+            paperListShow:[],
+            paperList:{
+                tmd:[],
+                school:[]
+            },
+        }
+	},
+    methods:{
+        handleSetTime(value){
+            let start = value[0]
+            let end = value[1]
+            this.subjectSetting.startTime = start ? new Date(start).getTime() : 0
+            this.subjectSetting.endTime = end ? new Date(end).getTime() : 0
+            console.log(value,this.subjectSetting)
+        },
+        async previewTestPaper(index){
+            this.previewPaper = {}
+            try {
+                this.paperListShow[index].scope = 'school'
+                this.previewPaper = await this.$evTools.getFullPaper(this.paperListShow[index])
+                setTimeout(() => {
+                    this.isPreview = true
+                }, 400)
+            } catch (e) {
+            }
+        },
+        choosePaper(index){
+            this.subjectSetting.paper = this.paperListShow[index]
+            this.sltPaperStatus = false
+        },
+        selectPaper(){
+            this.sltPaperStatus = true 
+            this.findPaperList()
+        },
+        findPaperList(){
+            if(!this.paperResource){
+                this.$Messag.error('参数异常')
+            }
+            if(this.paperResource == 'hbcn' && this.paperList.tmd.length){
+                return this.paperListShow = this.paperList.tmd
+            }
+            if(this.paperList.school.length){
+                return this.paperListShow = this.paperList.school
+            }
+            let params = {
+                schoolCode:this.paperResource
+            }
+            this.$api.areaArt.findArtPaperList(params).then(
+                res=>{
+                    if(this.paperResource === 'hbcn'){
+                        this.paperList.tmd = res.papers
+                    }else{
+                        this.paperList.school = res.papers
+                    }
+                    this.paperListShow = res.papers
+                }
+            )
+        },
+    },
+    watch:{
+        subjectSetting:{
+            deep:true,
+            handler(n,o){
+                this.$emit('on-exam-change',{
+                    data:this.subjectSetting,
+                    subject: this.subject
+                })
+            }
+        }
+    }
+    // mounted(){
+    //     setTimeout(() => {
+    //         this.subjectSetting.unorder = true
+    //     }, 2000);
+    // }
+
+}
+</script>
+
+<style lang="less" scoped>
+.attr-item{
+    margin-bottom: 10px;
+}
+.subject-content{
+    display: inline-block;
+    width: calc(100% - 80px);
+    vertical-align: top;
+}
+.back-to-list{
+    color: #2d8cf0;
+    cursor: pointer;
+    user-select: none;
+}
+.paper-item {
+    padding: 10px 15px;
+    position: relative;
+    // margin-left: 15px;
+    margin-right: 15px;
+    margin-bottom: 5px;
+    // background: #505050;
+    align-items: start;
+    border-radius: 2px;
+    position: relative;
+
+    &:hover {
+        background: #E1EFF6;
+        // box-shadow: 0px 4px 5px #191919;
+    }
+
+    &-name {
+        font-size: 20px;
+        font-weight: bold;
+    }
+
+    &-tag {
+        font-size: 12px;
+        padding: 1px 10px;
+        border-radius: 5px;
+        color: #fff;
+        background: #15a06c;
+        margin: 0 10px;
+    }
+
+    &-info {
+        margin-top: 15px;
+
+        .info-item {
+            font-size: 12px;
+            padding: 0 10px;
+            color: #757575;
+
+            .info-bold {
+                font-weight: bold;
+                color: #70B1E7;
+            }
+        }
+
+        .info-item:not(:last-child) {
+            border-right: 2px solid #f3f3f3;
+        }
+    }
+
+    &-tools {
+        position: absolute;
+        height: 100%;
+        right: 50px;
+        top: 35px;
+        font-size: 14px;
+        display: none;
+
+        span {
+            cursor: pointer;
+            font-weight: bold;
+            color: #1CC0F3;
+           /*  &:hover{
+                color:#2d8cf0;
+            }*/
+        }
+    }
+
+    &:hover {
+        .paper-item-tools {
+            display: flex;
+        }
+    }
+}
+.papaer-list-wrap{
+    height: 600px;
+}
+.choose-paper{
+    color: #2d8cf0;
+    cursor: pointer;
+}
+</style>

+ 63 - 0
TEAMModelOS/ClientApp/src/view/artexam/ExamSubject.vue

@@ -0,0 +1,63 @@
+<template>
+	<div class="content-block">
+		<CheckboxGroup v-model="baseKn.subjects"  @on-change="handleSetKn">
+			<div class="check-item">
+				<Checkbox label="paint">
+					<span class="subject-name">美术</span>
+				</Checkbox>
+				<ExamSetting v-if="baseKn.subjects.includes('paint')" :subject="'paint'" @on-exam-change="handleExamInfo"></ExamSetting>
+			</div>
+			<div>
+				<Checkbox label="music">
+					<span class="subject-name">音乐</span>
+				</Checkbox>
+				<ExamSetting v-if="baseKn.subjects.includes('music')" :subject="'music'" @on-exam-change="handleExamInfo"></ExamSetting>
+			</div>
+		</CheckboxGroup>
+	</div>
+</template>
+
+<script>
+import ExamSetting from "./ExamSetting.vue"
+export default {
+    components:{
+        ExamSetting
+    },
+	data() {
+		return {
+			unorder1:0,
+			unorder2:0,
+            baseKn:{
+				subjects:[],
+				settings:[]
+			}
+        }
+	},
+	methods:{
+		handleSetKn(){
+			this.$emit('on-set-exam',this.baseKn)
+		},
+		handleExamInfo(data){
+			data = this._.cloneDeep(data)
+			let index = this.baseKn.settings.findIndex(item=>item.subject == data.subject)
+			if(index > -1){
+				this.baseKn.settings.splice(index,1,Object.assign({subject:data.subject},data.data))
+			}else{
+				this.baseKn.settings.push(Object.assign({subject:data.subject},data.data))
+			}
+			this.handleSetKn()
+		}
+	}
+}
+</script>
+
+<style lang="less" scoped>
+.content-block{
+	background: #f0f0f0;
+	padding: 8px 5px;
+	margin: 10px 0px;
+}
+.check-item{
+    margin-bottom: 10px;
+}
+</style>

+ 139 - 0
TEAMModelOS/ClientApp/src/view/artexam/Mgt.vue

@@ -0,0 +1,139 @@
+<template>
+	<div class="art-exam-container">
+		<Split v-model="split">
+			<div class="demo-split-pane" slot="left">
+				<div class="art-mgt-top light-iview-select light-iview-input">
+					<span>艺术评价活动</span>
+					<span class="to-create-art" @click="toCreate">
+						<Icon type="md-add" />
+						创建艺术评测
+					</span>
+				</div>
+				<vuescroll>
+					<div :class="['art-item', curIndex == index ? 'art-item-active' : '']" v-for="(item,index) in artList" :key="item.id" @click="selectArt(index)">
+						<p>{{item.name}}</p>
+					</div>
+				</vuescroll>
+				<EmptyData v-show="!artList.length" :top="100"></EmptyData>
+			</div>
+			<div class="art-content" slot="right">
+				<vuescroll>
+					<div class="train-block-box">
+						{{artInfo.name}}
+					</div>
+				</vuescroll>
+			</div>
+        </Split>
+		
+		
+	</div>
+</template>
+
+<script>
+export default {
+	data() {
+		return {
+			split:0.25,
+			artList: [],
+			artInfo:{},
+			curIndex:0,
+			quotas:[],
+		}
+	},
+	methods: {
+		selectArt(index){
+			this.curIndex = index
+			this.findArtSummary()
+		},
+		/* 获取当前区级设置数据 */
+		getAreaSetting() {
+			this.$api.areaArt.findArtSetting({
+				areaId: sessionStorage.getItem("areaId")
+			}).then((res) => {
+				if (res.setting) {
+					console.log(res)
+					// this.artDimensions = res.setting.dimensions
+					this.quotas = res.setting.quotas
+					this.tabList = this.quotas.map((q) => {
+						return {
+							name: q.id,
+							label: q.name,
+							children: q.children
+						}
+					})
+				} else {
+					this.artDimensions = []
+				}
+			})
+		},
+		toCreate() {
+			this.$router.push({
+				name: "createArtExam"
+			})
+		},
+		toDetailPage(index) {},
+		findArtList() {
+			let params = {
+				code: this.$store.state.userInfo.schoolCode
+			}
+			this.$api.areaArt.findArtList(params).then(
+				(res) => {
+					this.artList = res.arts
+					if(this.artList.length) this.findArtSummary()
+				},
+				(err) => {}
+			)
+		},
+		findArtSummary(){
+			let params = {
+				id:this.artList[this.curIndex].id,
+				code: this.$store.state.userInfo.schoolCode
+			}
+			this.$api.areaArt.findArtSummary(params).then(
+				(res) => {
+					this.artInfo = res.art
+				},
+				(err) => {}
+			)
+		}
+	},
+	created(){
+		this.findArtList()
+	}
+}
+</script>
+
+<style lang="less" scoped>
+.art-content{
+	padding-left: 10px;
+}
+.art-item-active{
+	background: var(--hover-text-color);
+}
+.art-item{
+	padding: 15px 15px;
+	cursor: pointer;
+	&:hover{
+		background: var(--hover-text-color);
+	}
+}
+.art-exam-container {
+	width: 100%;
+	height: 100%;
+	background: white;
+}
+.art-mgt-top {
+	height: 45px;
+	box-shadow: 0px 2px 5px #e9e9e9;
+	padding-left: 15px;
+	padding-right: 20px;
+	margin-bottom: 5px;
+	line-height: 45px;
+}
+.to-create-art {
+	float: right;
+	user-select: none;
+	cursor: pointer;
+	color: #40a8f0;
+}
+</style>

+ 179 - 0
TEAMModelOS/ClientApp/src/view/artexam/QuoTree.vue

@@ -0,0 +1,179 @@
+<template>
+	<el-tree
+		show-checkbox
+		:data="treeData"
+		:props="defaultProps"
+		class="quo-tree"
+		node-key="id"
+		ref="tree"
+		:render-content="renderContent"
+        @check="hanldeCheckChange"
+		:render-after-expand="false"
+	></el-tree>
+</template>
+
+<script>
+import ExamSubject from "./ExamSubject.vue"
+import WorkSubject from "./WorkSubject.vue"
+export default {
+	components: {
+		ExamSubject,
+		WorkSubject
+	},
+	props: {
+		quoid: {
+			type: String,
+			default: ""
+		},
+		treeData: {
+			type: Array,
+			default: () => {
+				return []
+			}
+		}
+	},
+	data() {
+		return {
+			defaultProps: {
+				children: "children",
+				label: "name"
+			},
+			typeMap: {},
+			settingMap: {}
+		}
+	},
+	methods: {
+		renderContent(h, { node, data, store }) {
+			console.log(arguments)
+			let _this = this
+			// 不是最后一个节点则直接渲染label
+			if (node.childNodes.length) {
+				return h("span", {}, node.label)
+			} else {
+				if (!_this.typeMap[node.data.id])
+					_this.$set(_this.typeMap, node.data.id, "score")
+				return h(
+					"div",
+					{
+						style: {
+							width: "100%"
+						}
+					},
+					[
+						h("span", node.label),
+						h(
+							"RadioGroup",
+							{
+								class: "type-setting",
+								props: {
+									value: _this.typeMap[node.data.id]
+								},
+								on: {
+									input: (event) => {
+										_this.typeMap[node.data.id] = event
+										// _this.$set(_this.typeMap,node.data.id,event)
+										console.log(_this.typeMap, node.data.id)
+										// console.log(event)
+										// _this.$emit("input", event)
+									}
+								},
+								style: {
+									display: node.checked ? undefined : "none"
+								}
+							},
+							[
+								h(
+									"Radio",
+									{
+										props: {
+											label: "score"
+										}
+									},
+									"评分"
+								),
+								h(
+									"Radio",
+									{
+										props: {
+											label: "exam"
+										}
+									},
+									"评测"
+								),
+								h(
+									"Radio",
+									{
+										props: {
+											label: "work"
+										}
+									},
+									"作业"
+								)
+							]
+						),
+						node.checked && _this.typeMap[node.data.id] === "exam"
+							? h(ExamSubject, {
+									on: {
+										"on-set-exam": (data) => {
+											console.log("****", data)
+											_this.$set(_this.settingMap,node.data.id,data)
+										}
+									}
+							  })
+							: undefined,
+						node.checked && _this.typeMap[node.data.id] === "work"
+							? h(WorkSubject, {
+									on:{
+										"on-set-work": (data) => {
+											console.log(data)
+											_this.$set(_this.settingMap,node.data.id,data)
+										}
+									}
+							  })
+							: undefined
+					]
+				)
+			}
+		},
+        hanldeCheckChange(data,status){
+            this.$emit('on-check-change',{
+                quoid:this.quoid,
+                data:status
+            })
+        }
+	},
+    watch:{
+        typeMap:{
+            deep:true,
+            handler(n,o){
+                this.$emit('on-type-change',{
+                    quoid:this.quoid,
+                    data:n
+                })
+            }
+        },
+        settingMap:{
+            deep:true,
+            handler(n,o){
+                this.$emit('on-setting-change',{
+                    quoid:this.quoid,
+                    data:n
+                })
+            }
+        },
+    }
+
+}
+</script>
+
+<style lang="less" scoped>
+</style>
+<style lang="less">
+.type-setting {
+	float: right;
+}
+.quo-tree .el-tree-node__content {
+	height: fit-content;
+	align-items: baseline;
+}
+</style>

+ 66 - 0
TEAMModelOS/ClientApp/src/view/artexam/WorkSetting.vue

@@ -0,0 +1,66 @@
+<template>
+    <div class="work-setting-container">
+        <!-- 作业描述 -->
+		<div class="attr-item">
+			<span style="vertical-align: top;">作业描述:</span>
+            <Input @on-change="handleSetWork" v-model="workSetting.desc" type="textarea" maxlength="100" :rows="2" style="width:500px" placeholder="请输入作业描述..." />
+		</div>
+        <!-- 截止时间 -->
+		<div class="attr-item">
+			<span>截止时间:</span>
+			<DatePicker
+                transfer
+				type="datetime"
+				placement="bottom-start"
+				placeholder="请设置作业截止时间"
+                @on-change="handleSetTime"
+                style="width:500px"
+			></DatePicker>
+		</div>
+    </div>
+</template>
+
+<script>
+    export default {
+        props:{
+            subject:{
+                type:String,
+                default:'',
+                required:true
+            }
+        },
+        data(){
+            return{
+                workSetting:{
+                    startTime:0,
+                    endTime:0,
+                    desc:''
+                }
+            }
+        },
+        methods:{
+            handleSetWork(){
+                this.$emit('on-set-work',{
+                    subject: this.subject,
+                    data:this.workSetting
+                })
+            },
+            handleSetTime(value){
+                this.workSetting.endTime = value ? new Date(value).getTime() : 0
+                console.log(value,this.workSetting)
+                this.handleSetWork()
+            },
+        }
+    }
+</script>
+
+<style lang="less" scoped>
+.work-setting-container{
+    display: inline-block;
+    width: calc(100% - 80px);
+    vertical-align: top;
+}
+.attr-item{
+    margin-bottom: 10px;
+}
+</style>

+ 61 - 0
TEAMModelOS/ClientApp/src/view/artexam/WorkSubject.vue

@@ -0,0 +1,61 @@
+<template>
+	<div class="content-block">
+		<CheckboxGroup v-model="baseWork.subjects"  @on-change="handleSetWork">
+			<div class="check-item">
+				<Checkbox label="paint">
+					<span class="subject-name">美术</span>
+				</Checkbox>
+				<WorkSetting v-if="baseWork.subjects.includes('paint')" subject="paint" @on-set-work="handleWorkInfo"></WorkSetting>
+			</div>
+			<div>
+				<Checkbox label="music">
+					<span class="subject-name">音乐</span>
+				</Checkbox>
+				<WorkSetting v-if="baseWork.subjects.includes('music')" subject="music" @on-set-work="handleWorkInfo"></WorkSetting>
+			</div>
+		</CheckboxGroup>
+	</div>
+</template>
+
+<script>
+import WorkSetting from "./WorkSetting.vue"
+export default {
+	components:{
+		WorkSetting
+	},
+	data(){
+		return{
+			baseWork:{
+				subjects:[],
+				settings:[]
+			}
+		}
+	},
+	methods:{
+		handleSetWork(){
+			this.$emit('on-set-work',this.baseWork)
+		},
+		handleWorkInfo(data){
+			data = this._.cloneDeep(data)
+			let index = this.baseWork.settings.findIndex(item=>item.subject == data.subject)
+			if(index > -1){
+				this.baseWork.settings.splice(index,1,Object.assign({subject:data.subject},data.data))
+			}else{
+				this.baseWork.settings.push(Object.assign({subject:data.subject},data.data))
+			}
+			this.handleSetWork()
+		}
+	}
+}
+</script>
+
+<style lang="less" scoped>
+.check-item{
+    margin-bottom: 10px;
+}
+.content-block{
+	background: #f0f0f0;
+	padding: 8px 5px;
+	margin: 10px 0px;
+}
+</style>

+ 0 - 4
TEAMModelOS/ClientApp/src/view/learnactivity/ManualPaper.vue

@@ -45,10 +45,6 @@
                         <span>{{(index + 1) + '.  ' + item.name}}</span>
                     </div>
                     <div class="paper-item-info">
-                        <!-- <span class="info-item" v-show="scope == $store.state.userInfo.schoolCode">
-                            {{$t('learnActivity.manual.fitPd')}}
-                            <span class="info-bold">{{$jsFn.getPeriod(schoolBase.period,item.periodId).name}}</span>
-                        </span> -->
                         <span class="info-item" v-show="scope == $store.state.userInfo.schoolCode">
                             {{$t('learnActivity.manual.fitSubject')}}
                             <span class="info-bold">{{item.subjectName}}</span>

+ 4 - 1
TEAMModelOS/ClientApp/src/view/learnactivity/markpaper/MarkData.vue

@@ -256,7 +256,7 @@ export default {
                         })
                         // 数据生成中,重新请求,最多请求5次
                         if (isUncomplete) {
-                            if(this.reqCount < this.maxReq){
+                            if(this.reqCount++ < this.maxReq){
                                 this.timer = setTimeout(()=>{
                                     this.findMarkProgress()
                                 },1500)
@@ -319,6 +319,9 @@ export default {
             },
             immediate: true
         }
+    },
+    beforeDestroy(){
+        clearTimeout(this.timer)
     }
 }
 </script>

+ 6 - 1
TEAMModelOS/ClientApp/src/view/mycourse/MyCourse.vue

@@ -56,6 +56,9 @@
                                     <span class="attr-label" v-show="listType === 'school'">{{item.classId ? $t('cusMgt.listType1') : $t('cusMgt.listType2')}}: </span>
                                     <span class="attr-label" v-show="listType === 'private'">{{$t('cusMgt.nameList')}}:</span>
                                     <span class="class-name">{{item.classId ? item.classInfo.name: item.listName || '--'}}</span>
+                                    <Tag v-if="item.graduate === 1" color="gold">
+                                        {{$t('cusMgt.hasGraduate')}}
+                                    </Tag>
                                     <span class="relative-tag" v-if="item.stulistRel > 1">{{$t('cusMgt.reuse')}}</span>
                                 </p>
                                 <p class="class-attr-item">
@@ -1014,7 +1017,8 @@ export default {
                                                 name: classInfo ? classInfo.name : this.$t('cusMgt.hasDelClass'),
                                                 year: classInfo ? classInfo.year : 0 //方便计算年级
                                             }
-                                            item.joinLock = classInfo.joinLock
+                                            item.joinLock = classInfo?.joinLock
+                                            item.graduate = classInfo?.graduate
                                         }
                                         //补充教学班信息
                                         if (item.stulist) {
@@ -1024,6 +1028,7 @@ export default {
                                             item.listName = listInfo ? listInfo.name : this.$t('cusMgt.hasDelClass')
                                             item.listSchool = listInfo ? listInfo.school : undefined
                                             item.joinLock = listInfo?.joinLock
+                                            item.graduate = listInfo?.graduate
                                         }
                                         //统一数据格式
                                         item.classId = item.classId || undefined

+ 1 - 2
TEAMModelOS/ClientApp/src/view/student-account/import/StuImport.vue

@@ -515,7 +515,7 @@ export default {
         },
         checkData() {
             //整理TtableData
-            this.tableData.map((item, index) => {
+            this.tableData.forEach((item, index) => {
                 if (!item.pw) item.pw = item.id
                 item['classroom'] = {}
                 item.classroom.classId = item.classId
@@ -523,7 +523,6 @@ export default {
                 item.year = item.stuYear
                 item.no = item.no ? item.no.toString() : ''
                 item.periodId = this.periodId
-                return item
             })
 
             //座号重复检查逻辑

+ 16 - 1
TEAMModelOS/ClientApp/src/view/train/TrainDetail.vue

@@ -526,6 +526,7 @@ export default {
     },
     data() {
         return {
+            repeatCount:0,
             updHeader: {},
             hwPreviewFile: {},
             modalLoading: false,
@@ -1690,7 +1691,21 @@ export default {
                                     })
                                     // 现在研修会记录发布活动时的名单,不需要单独活动名单(解决名单调整问题)
                                     // this.getTeachers()
-                                    this.handleData(res.ufos)
+                                    //后端数据生成可能有延迟,需要循环拉取数据
+                                    debugger
+                                    if(!res.ufos?.length){
+                                        if(this.repeatCount < 5){
+                                            this.repeatCount++
+                                            setTimeout(() => {
+                                                this.getTrainInfo(id)
+                                            }, 1000)
+                                        }else{
+                                            this.$Message.warning('活动暂无名单数据,或者数据生成中,请稍后重试')
+                                            this.repeatCount = 0
+                                        }
+                                    }else{
+                                        this.handleData(res.ufos)
+                                    }
                                 }
                             }
                         }