123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426 |
- <template>
- <div class="grading-level-set">
- <Button
- class="level-add-btn"
- type="success"
- icon="recode-white icon"
- shape="circle"
- @click="toAdd"
- >新增档位</Button
- >
- <table class="table table-noborder grading-table">
- <tr>
- <th>档位</th>
- <th>最低分</th>
- <th>最高分</th>
- <th>给分间隔</th>
- <th>典型值</th>
- <th>类型</th>
- <th>给分项</th>
- <th>考区阈值%</th>
- <th>占比阈值%</th>
- <th>操作</th>
- </tr>
- <template v-for="(level, index) in levels">
- <tr :key="index">
- <td>
- <Input
- v-model="level.code"
- style="width: 60px"
- @on-blur="codeChange(level)"
- v-if="level.canEdit && workDetail.modifyOtherVal"
- ></Input>
- <p v-else>{{ level.code }}</p>
- </td>
- <td>
- <InputNumber
- v-model="level.minScore"
- :min="0"
- :max="1000"
- @on-blur="checkLevelValidate(level)"
- v-if="level.canEdit && workDetail.modifyOtherVal"
- ></InputNumber>
- <p v-else>{{ level.minScore }}</p>
- </td>
- <td>
- <InputNumber
- v-model="level.maxScore"
- :min="1"
- :max="1000"
- @on-blur="checkLevelValidate(level)"
- v-if="level.canEdit && workDetail.modifyOtherVal"
- ></InputNumber>
- <p v-else>{{ level.maxScore }}</p>
- </td>
- <td style="min-width: 100px">
- <InputNumber
- v-model="level.intervalScore"
- :min="1"
- :max="100"
- :precision="0"
- :disabled="!level.canEdit"
- @on-blur="checkLevelValidate(level)"
- v-if="
- level.levelType === 'ADMITED' &&
- level.canEdit &&
- workDetail.modifyOtherVal
- "
- ></InputNumber>
- <p v-else>{{ level.intervalScore }}</p>
- </td>
- <td>
- <InputNumber
- v-model="level.weight"
- :min="1"
- :max="1000"
- @on-blur="checkLevelValidate(level)"
- v-if="level.canEdit && workDetail.modifyOtherVal"
- ></InputNumber>
- <p v-else>{{ level.weight }}</p>
- </td>
- <td>
- <Select
- v-model="level.levelType"
- @on-change="levelTypeChange(level)"
- style="width: 120px"
- v-if="level.canEdit && workDetail.modifyOtherVal"
- >
- <Option
- v-for="(val, key) in LEVEL_TYPE"
- :key="key"
- :value="key"
- >{{ val }}</Option
- >
- </Select>
- <p v-else>{{ LEVEL_TYPE[level.levelType] }}</p>
- </td>
- <td style="min-width: 140px">
- <Input
- v-model="level.scoreList"
- @on-blur="checkLevelValidate(level)"
- v-if="
- level.levelType === 'UNADMIT' &&
- level.canEdit &&
- workDetail.modifyOtherVal
- "
- ></Input>
- <p v-else>{{ level.scoreList }}</p>
- </td>
- <td>
- <InputNumber
- v-model="level.kdpt"
- :min="1"
- :max="100"
- @on-blur="checkLevelValidate(level)"
- v-if="level.canEdit"
- ></InputNumber>
- <p v-else>{{ level.kdpt }}</p>
- </td>
- <td>
- <InputNumber
- v-model="level.pt"
- :min="1"
- :max="100"
- @on-blur="checkLevelValidate(level)"
- v-if="level.canEdit"
- ></InputNumber>
- <p v-else>{{ level.pt }}</p>
- </td>
- <td class="table-action">
- <div style="width: 60px">
- <Icon type="md-create" title="编辑" @click="toEdit(index)" />
- <Icon
- class="icon-danger"
- type="md-trash"
- title="删除"
- @click="toDelete(index)"
- v-if="workDetail.modifyOtherVal"
- />
- </div>
- </td>
- </tr>
- <tr class="tr-tips-error" v-if="level.errors" :key="index + '1'">
- <td>
- {{ level.errors.code }}
- </td>
- <td>
- {{ level.errors.minScore }}
- </td>
- <td>
- {{ level.errors.maxScore }}
- </td>
- <td>
- {{ level.errors.intervalScore }}
- </td>
- <td>
- {{ level.errors.weight }}
- </td>
- <td></td>
- <td>
- {{ level.errors.scoreList }}
- </td>
- <td>
- {{ level.errors.kdpt }}
- </td>
- <td>
- {{ level.errors.pt }}
- </td>
- <td></td>
- </tr>
- </template>
- </table>
- <div class="text-center">
- <Button
- type="primary"
- shape="circle"
- @click="toSubmit"
- style="width: 80px"
- :disabled="isSubmit"
- >确定</Button
- >
- </div>
- </div>
- </template>
- <script>
- import { workDetail, updateWork } from "@/api";
- import { LEVEL_TYPE } from "@/constants/enumerate";
- import schema from "async-validator";
- schema.warning = function () {};
- const initLevel = {
- id: null,
- workId: null,
- code: null,
- levelValue: 0,
- maxScore: null,
- minScore: null,
- intervalScore: null,
- weight: null,
- levelType: "ADMITED",
- scoreList: null,
- pt: null,
- kdpt: null,
- };
- export default {
- name: "grading-level-set",
- data() {
- return {
- LEVEL_TYPE,
- workId: this.$route.params.workId,
- letterRelateNumber: {},
- levels: [],
- workDetail: {},
- isSubmit: false,
- };
- },
- mounted() {
- this.initData();
- },
- methods: {
- initData() {
- const letters = "ABCDEFGHIJKLMNOPQRSTUVWXYZ";
- letters.split("").map((item, index) => {
- this.letterRelateNumber[item] = index + 1;
- });
- this.getData();
- },
- async getData() {
- const data = await workDetail(this.workId);
- this.workDetail = data;
- this.levels = data.levels.map((item) => {
- item.canEdit = false;
- return item;
- });
- },
- checkLevelCodeIsContinuous() {
- let levelIsContinuous = true;
- for (var i = 0, num = this.levels.length; i < num; i++) {
- if (i > 0) {
- const beforeCodeNum =
- this.letterRelateNumber[this.levels[i - 1].code];
- const curCodeNum = this.letterRelateNumber[this.levels[i].code];
- levelIsContinuous =
- levelIsContinuous && curCodeNum - beforeCodeNum === 1;
- if (!levelIsContinuous) {
- return false;
- }
- }
- }
- return true;
- },
- levelTypeChange(level) {
- if (level.levelType === "ADMITED") {
- level.scoreList = null;
- } else {
- level.intervalScore = null;
- }
- },
- codeChange(level) {
- level.code = level.code.toUpperCase();
- this.levels.sort((a, b) => {
- if (
- !a.code ||
- !b.code ||
- !this.letterRelateNumber[a.code] ||
- !this.letterRelateNumber[b.code]
- )
- return 0;
- return (
- this.letterRelateNumber[a.code] - this.letterRelateNumber[b.code]
- );
- });
- this.checkLevelValidate(level);
- },
- getNextLevelCode() {
- const codeNumbers = this.levels.map(
- (level) => this.letterRelateNumber[level.code] || 0
- );
- const maxCodeNumber = Math.max.apply(null, codeNumbers);
- const nextLevel = Object.entries(this.letterRelateNumber).find(
- ([key, val]) => {
- return maxCodeNumber < val;
- }
- );
- return nextLevel ? nextLevel[0] : "";
- },
- toAdd() {
- let level = { ...initLevel };
- level.workId = this.workId;
- level.code = this.getNextLevelCode();
- this.levels.push(level);
- },
- toEdit(index) {
- this.levels[index].canEdit = true;
- this.$forceUpdate();
- },
- toDelete(index) {
- this.levels.splice(index, 1);
- },
- checkLevelValidate(level) {
- const descriptor = {
- code: {
- type: "string",
- required: true,
- pattern: /^[A-Z]{1}$/,
- message: "请输入单个大写字母",
- },
- minScore: {
- type: "number",
- required: true,
- message: "请输入最低分",
- },
- maxScore: {
- type: "number",
- required: true,
- validator: (rule, value, callback) => {
- if (!value || value < level.minScore) {
- callback(new Error("最高分不得小于最低分"));
- } else {
- callback();
- }
- },
- },
- intervalScore: {
- type: "number",
- validator: (rule, value, callback) => {
- if (level.levelType === "ADMITED" && !value) {
- callback(new Error("请输入给分间隔"));
- } else {
- callback();
- }
- },
- },
- weight: {
- type: "number",
- required: true,
- message: "请输入典型值",
- },
- scoreList: {
- type: "string",
- validator: (rule, value, callback) => {
- if (level.levelType !== "UNADMIT") return callback();
- if (level.levelType === "UNADMIT" && !value) {
- return callback(new Error("请输入给分项"));
- }
- if (!value.match(/^[0-9,]+$/)) {
- return callback(new Error("给分项只能包含数字和英文逗号"));
- }
- const unvalid = value
- .split(",")
- .filter((item) => item)
- .some((item) => {
- const num = item * 1;
- return num < level.minScore || num > level.maxScore;
- });
- if (unvalid) {
- return callback(
- new Error("给分项包含的分值只能介于最低分和最高分之间")
- );
- }
- callback();
- },
- },
- pt: {
- type: "number",
- required: true,
- message: "请输入占比阀值",
- },
- kdpt: {
- type: "number",
- required: true,
- message: "请输入考区阀值",
- },
- };
- return new schema(descriptor)
- .validate(level)
- .then(() => {
- if (level.errors) level.errors = null;
- })
- .catch(({ errors, fields }) => {
- let errorMsgs = {};
- errors.map((error) => {
- errorMsgs[error.field] = error.message;
- });
- this.$set(level, "errors", errorMsgs);
- return { errors };
- });
- },
- async toSubmit() {
- const validatorAll = this.levels.map((level) =>
- this.checkLevelValidate(level)
- );
- const result = await Promise.all(validatorAll);
- const hasUnvalidate = result.some((item) => !!item);
- if (hasUnvalidate) return;
- if (!this.checkLevelCodeIsContinuous()) {
- this.$Message.error("请保持档位连续!");
- return;
- }
- if (this.isSubmit) return;
- this.isSubmit = true;
- this.workDetail.levels = this.levels;
- const data = await updateWork(this.workDetail).catch(() => {
- this.isSubmit = false;
- });
- if (!data) return;
- this.isSubmit = false;
- this.getData();
- this.$Message.success("保存成功!");
- },
- },
- };
- </script>
|