Selaa lähdekoodia

add:新增批量录单-未完善

Tang 3 vuotta sitten
vanhempi
commit
179b861d2f

+ 16 - 0
src/newApi/orderConfigBusiness.js

@@ -31,4 +31,20 @@ export default {
             method: 'get',
         })
     },
+    //导入用户
+    appuserimportData(data) {
+        return request({
+            url: '/app/user/importData',
+            method: 'post',
+            data
+        })
+    },
+    //导出失败导入用户
+    appuserimporexportFailData(data) {
+        return request({
+            url: '/app/user/exportFailData',
+            method: 'post',
+            data
+        })
+    },
 }

+ 1 - 1
src/store/modules/tagsView.js

@@ -2,7 +2,7 @@ import { MessageBox } from 'element-ui';
 const state = {
   visitedViews: [],
   cachedViews: [],
-  alertPage: ["CommodityManageMentAdd", "CommodityManageMentEdit", "FestivalAdd", "FestivalEdit", "ChapterAdd", "ChapterEdit", "ModuleManagementAdd", "ModuleManagementEdit", "BasicInfoEdit", "BasicInfoAdd", "ChapterContent", "EditCourse", "OrderDetail", "OrderPrice", "AddOrder", "EditPaper", "AddPaper", "TopicAddPaper", "ChapterVolumeManagementEdit", "ChapterVolumeManagementAdd", "VolumeManagementAdd", "VolumeManagementEdit", "HandoutListEdit", "HandoutListAdd", "StudentXQ", "AddClass", "ManageClass", "NotificationInfo", "NotificationListAdd", "NotificationEdit", "BulkImportPlan", "MatchInfoData"],
+  alertPage: ["CommodityManageMentAdd", "CommodityManageMentEdit", "FestivalAdd", "FestivalEdit", "ChapterAdd", "ChapterEdit", "ModuleManagementAdd", "ModuleManagementEdit", "BasicInfoEdit", "BasicInfoAdd", "ChapterContent", "EditCourse", "OrderDetail", "OrderPrice", "AddOrder", "EditPaper", "AddPaper", "TopicAddPaper", "ChapterVolumeManagementEdit", "ChapterVolumeManagementAdd", "VolumeManagementAdd", "VolumeManagementEdit", "HandoutListEdit", "HandoutListAdd", "StudentXQ", "AddClass", "ManageClass", "NotificationInfo", "NotificationListAdd", "NotificationEdit", "BulkImportPlan", "MatchInfoData","BatchRecord"],
 }
 
 const mutations = {

+ 12 - 0
src/utils/methodsTool.js

@@ -374,6 +374,18 @@ export default {
 			return []
 		}
 	},
+    /**
+	 * 
+	 * @param {Arrays} arr 数据
+	 * @param {Strings} uniId 根据哪个参数去重
+	 * @returns 对象数组去重
+	 */
+    uniqueFunc(arr, uniId) {
+      const res = new Map();
+      return arr.filter(
+        (item) => !res.has(item[uniId]) && res.set(item[uniId], 1)
+      );
+    },
 	/**
 	 *
 	 * @param {Bool} status true 全部 false 筛选

+ 1 - 1
src/utils/request.js

@@ -15,7 +15,7 @@ axios.defaults.headers['Content-Type'] = 'application/json;charset=utf-8'
 /**
  * @remard 测试地址
  */
-export const baseURL = 'http://192.168.1.222:5030/'
+export const baseURL = 'http://192.168.1.24:5030/'
 export const BASE_IMG_URL = 'https://file-dev.xyyxt.net'
 const service = axios.create({
   // axios中请求配置有baseURL选项,表示请求URL公共部分

+ 425 - 0
src/views/Marketing/order/offlineOrder/batchRecord/firstStep/addStudent.vue

@@ -0,0 +1,425 @@
+<template>
+  <div id="addStudent">
+    <el-dialog
+      @closed="loadingClose"
+      :visible.sync="dialogVisible"
+      width="960px"
+      :show-close="false"
+      :close-on-click-modal="false"
+    >
+      <div slot="title" class="hearders">
+        <div class="leftTitle">添加学员</div>
+        <div class="rightBoxs">
+          <img src="@/assets/images/Close@2x.png" alt="" @click="close" />
+        </div>
+      </div>
+      <div>
+        <search-box-new
+          ref="searchBox"
+          :formData="formData"
+          :formList="formList"
+          @search="openBox(true)"
+          @init="init"
+          :advanced="true"
+          @Advanced="advanced"
+          advancedName="高级输入"
+        />
+        <el-table
+          v-loading="loading"
+          border
+          :data="tableData"
+          row-key="userId"
+          @selection-change="selectionChange"
+          style="width: 100%; margin-top: 16px"
+          ref="elTable"
+          max-height="529px"
+          ><el-table-column
+            type="selection"
+            width="55"
+            align="center"
+            reserve-selection
+            :selectable="selectableFunc"
+          >
+          </el-table-column
+          ><el-table-column type="index" width="55" label="序号" align="center">
+          </el-table-column>
+          <el-table-column
+            align="center"
+            v-for="(item, index) in tableSet"
+            :key="index"
+            :prop="item.prop"
+            :label="item.label"
+            :width="item.width"
+          >
+            <template slot-scope="scope">
+              <span>{{ scope.row[item.prop] }}</span>
+            </template>
+          </el-table-column>
+        </el-table>
+        <pagination
+          :total="total"
+          :pageSize="formData.pageSize"
+          :currentPage="formData.pageNum"
+          @handleSizeChange="handleSizeChange"
+          @handleCurrentChange="handleCurrentChange"
+        />
+      </div>
+      <span slot="footer" class="dialog-footer">
+        <el-button @click="close">取 消</el-button>
+        <el-button
+          type="primary"
+          :loading="disabledBtn"
+          @click="submit"
+          :disabled="!selectArr.length"
+          >确 定</el-button
+        >
+      </span>
+    </el-dialog>
+    <el-dialog
+      append-to-body
+      :visible.sync="dialogPLS"
+      width="660px"
+      :show-close="false"
+      :close-on-click-modal="false"
+    >
+      <div slot="title" class="hearders">
+        <div class="leftTitle">高级输入</div>
+        <div class="rightBoxs">
+          <img
+            src="@/assets/images/Close@2x.png"
+            alt=""
+            @click="dialogPLS = false"
+          />
+        </div>
+      </div>
+      <el-row :gutter="20">
+        <el-col :span="12"
+          ><h4>请输入学员的身份证号码,换行隔开,每行一个</h4>
+          <el-input
+            type="textarea"
+            :rows="10"
+            placeholder="请输入身份证"
+            v-model="idcordList"
+          >
+          </el-input>
+        </el-col>
+        <el-col :span="12">
+          <h4>快捷导入</h4>
+          <el-link type="primary" @click="getDowm">下载模板</el-link>
+          <label
+            for="mobles"
+            class="el-button el-button--primary"
+            style="margin-left: 14px; padding: 10px 20px"
+            >上传学员名单</label
+          ><input
+            style="display: none"
+            type="file"
+            id="mobles"
+            ref="input1"
+            @change="importMobleadd"
+          />
+        </el-col>
+      </el-row>
+      <span slot="footer" class="dialog-footer">
+        <el-button @click="dialogPLS = false">取消</el-button>
+        <el-button type="primary" @click="submitChecksPals">确定</el-button>
+      </span>
+    </el-dialog>
+  </div>
+</template>
+
+<script>
+import * as baseUrls from "@/utils/request.js";
+import searchBoxNew from "@/components/searchBoxNew";
+import pagination from "@/components/pagination";
+export default {
+  components: { searchBoxNew, pagination },
+  data() {
+    return {
+      dialogPLS: false,
+      idcordList: "",
+      loading: false, //当前表单加载是否加载动画
+      dialogVisible: false,
+      disabledBtn: false,
+      tableData: [],
+      disCheckList: [1, 4, 6],
+      selectArr: [], //当前多选框选中数据
+      tableSet: [
+        {
+          label: "学员编码",
+          prop: "studentCode",
+        },
+        {
+          label: "学员姓名",
+          prop: "realname",
+        },
+        {
+          label: "学员身份证",
+          prop: "idCard",
+        },
+        {
+          label: "绑定手机号码",
+          prop: "telphone",
+        },
+      ],
+      total: 0,
+      //搜索
+      formList: [
+        {
+          prop: "searchKey",
+          placeholder: "请输入学员姓名/学员身份证",
+        },
+        {
+          prop: "idCards",
+          placeholder: "请输入学员身份证",
+          scope: "textarea",
+        },
+      ],
+      formData: {
+        pageSize: 10,
+        pageNum: 1,
+        idCards: "",
+        getOrderNum: 0,
+      },
+    };
+  },
+  methods: {
+    /**
+     * 高级输入确定触发
+     */
+    submitChecksPals() {
+      this.formData.idCards = this.idcordList;
+      this.dialogPLS = false;
+    },
+    /**
+     * 高级输入打开触发
+     */
+    advanced(datas) {
+      this.dialogPLS = true;
+      this.idcordList = this.formData.idCards;
+    },
+    /**
+     * 下载模板
+     */
+    getDowm() {
+      let url =
+        baseUrls.BASE_IMG_URL +
+        "/oss/images/file/20220214.xls" +
+        `?time=${this.$methodsTools.getNewTime()}`;
+      let link = document.createElement("a");
+      let fileName = "导入模板" + ".xlsx";
+      document.body.appendChild(link);
+      link.href = url;
+      link.dowmload = fileName;
+      link.click();
+      link.remove();
+    },
+    /**
+     * 导入
+     */
+    importMobleadd(e) {
+      var self = this;
+      var file = e.target.files[0];
+      let formData = new FormData();
+      formData.append("file", file);
+      this.$api
+        .editsystemimportIdsData(formData)
+        .then((res) => {
+          if (!res.data.length) {
+            this.$message.warning("未检测到上传学员数据,请检查上传文件");
+            return;
+          }
+          let idList = res.data.map((item) => {
+            return item.idCard.toString();
+          });
+          if (this.idcordList) {
+            var arr = this.idcordList.split("\n");
+            var arrs = arr.concat(idList);
+            var newArr = arrs.filter(function (value, index, self) {
+              return self.indexOf(value) === index;
+            });
+            this.idcordList = newArr.join("\n");
+          } else {
+            var newArr = idList.filter(function (value, index, self) {
+              return self.indexOf(value) === index;
+            });
+            this.idcordList = newArr.join("\n");
+          }
+          this.$message.success("上传成功");
+        })
+        .finally(() => {
+          e.target.value = "";
+        });
+    },
+    openBox(statust, int) {
+      this.loading = true;
+      if (int === 2) {
+        this.formData = {
+          pageSize: 10,
+          pageNum: 1,
+          idCards: "",
+          getOrderNum: 0,
+        };
+      }
+      var data = JSON.parse(JSON.stringify(this.formData));
+      if (this.formData.idCards) {
+        data.idCards = this.formData.idCards.split("\n");
+      }
+      if (this.formData.searchKey && this.formData.idCards) {
+        data.searchType = 1;
+      } else {
+        data.searchType = 0;
+      }
+      this.$api
+        .inquiregradestudentlistStudent(data)
+        .then((res) => {
+          this.tableData = res.rows;
+          this.total = res.total;
+          if (!statust) {
+            this.disCheckList = this.$parent.tableData.map((item) => {
+              return item.userId;
+            });
+            this.dialogVisible = true;
+            this.$nextTick(() => {
+              this.$refs.elTable.clearSelection();
+            });
+          }
+        })
+        .finally(() => {
+          this.loading = false;
+        });
+    },
+    loadingClose() {
+      this.disabledBtn = false;
+    },
+    close() {
+      this.dialogVisible = false;
+    },
+    init() {
+      this.openBox(true, 2);
+    },
+    submit() {
+      this.$parent.changeStudent(this.selectArr);
+      this.selectArr = [];
+      this.close();
+    },
+    /**
+     * 判断当前行是否允许勾选
+     */
+    selectableFunc(row, index) {
+      if (this.disCheckList.indexOf(row.userId) !== -1) {
+        return false;
+      } else {
+        return true;
+      }
+    },
+    /**
+     * 多选框变化触发
+     */
+    selectionChange(arr) {
+      this.selectArr = arr;
+    },
+    handleSizeChange(v) {
+      this.formData.pageSize = v;
+      this.formData.pageNum = 1;
+      this.openBox(true);
+    },
+    handleCurrentChange(v) {
+      this.formData.pageNum = v;
+      this.openBox(true);
+    },
+  },
+};
+</script>
+
+<style lang="less" scoped>
+/deep/.el-button {
+  border-radius: 8px;
+}
+/deep/.el-dialog {
+  border-radius: 8px;
+  .el-dialog__header {
+    padding: 0;
+    .hearders {
+      height: 40px;
+      display: flex;
+      align-items: center;
+      justify-content: space-between;
+      padding: 0px 18px 0px 20px;
+      border-bottom: 1px solid #e2e2e2;
+      .leftTitle {
+        font-size: 14px;
+        font-weight: bold;
+        color: #2f4378;
+      }
+      .rightBoxs {
+        display: flex;
+        align-items: center;
+        img {
+          width: 14px;
+          height: 14px;
+          margin-left: 13px;
+          cursor: pointer;
+        }
+      }
+    }
+  }
+  .el-dialog__footer {
+    padding: 0;
+    .dialog-footer {
+      padding: 0px 40px;
+      height: 70px;
+      border-top: 1px solid #e2e2e2;
+      display: flex;
+      align-items: center;
+      justify-content: flex-end;
+    }
+  }
+}
+.imgBox {
+  width: 100%;
+  // height: 210px;
+  border: 1px solid #e2e2e2;
+  border-radius: 8px;
+  padding: 8px 8px 3px;
+  display: flex;
+  flex-direction: column;
+  align-items: center;
+  .imgLabel {
+    flex: 1;
+    width: 100%;
+    border: 1px dotted #e2e2e2;
+    color: #999;
+    font-size: 14px;
+    cursor: pointer;
+    border-radius: 8px;
+    .msPhoto {
+      display: flex;
+      justify-content: center;
+      align-items: center;
+      max-width: 100%;
+      max-height: 270px;
+      img {
+        max-width: 100%;
+        max-height: 270px;
+      }
+    }
+    .imgbbx {
+      display: flex;
+      flex-direction: column;
+      align-items: center;
+      justify-content: center;
+      width: 100%;
+      height: 100%;
+      i {
+        font-weight: bold;
+        margin: 14px 0;
+        font-size: 24px;
+      }
+    }
+  }
+  p {
+    margin: 5px 0px;
+  }
+}
+</style>

+ 393 - 0
src/views/Marketing/order/offlineOrder/batchRecord/firstStep/index.vue

@@ -0,0 +1,393 @@
+<template>
+  <div id="firstStep">
+    <div class="topS">
+      <el-select
+        :size="size"
+        v-model="topData.educationId"
+        placeholder="请选择教育类型"
+        :disabled="tableData.length ? true : false"
+      >
+        <el-option
+          v-for="(items, indexs) in educationType"
+          :key="indexs"
+          :label="items.educationName"
+          :value="items.id"
+        ></el-option>
+      </el-select>
+      <!-- 业务层次 -->
+      <el-select
+        :disabled="tableData.length ? true : false"
+        v-if="topData.educationId"
+        v-model="topData.businessId"
+        placeholder="请选择业务层次"
+        :size="size"
+        style="margin-left: 10px"
+        @change="changeBusinessLevel"
+      >
+        <el-option
+          v-for="(items, indexs) in newBusinessLevel"
+          :key="indexs"
+          :label="items.projectName + '-' + items.businessName"
+          :value="items.id"
+        ></el-option>
+      </el-select>
+      <!-- 商品匹配模板 -->
+      <el-select
+        v-if="topData.businessId"
+        v-model="topData.configId"
+        placeholder="请选择商品匹配模板"
+        :size="size"
+        style="margin-left: 10px"
+      >
+        <el-option
+          v-for="(items, indexs) in configList"
+          :key="indexs"
+          :label="items.configName"
+          :value="items.id"
+        ></el-option>
+      </el-select>
+      <el-select
+        v-if="topData.configId"
+        v-model="topData.type"
+        multiple
+        collapse-tags
+        :size="size"
+        style="margin-left: 10px"
+        placeholder="请选择商品类型"
+      >
+        <el-option
+          v-for="item in typeList"
+          :key="item.value"
+          :label="item.label"
+          :value="item.value"
+        >
+        </el-option>
+      </el-select>
+      <template v-if="topData.type.length">
+        <el-button
+          style="margin-left: 10px"
+          :size="size"
+          type="primary"
+          @click="SELECTPEOPLE"
+          >添加学员</el-button
+        >
+        <el-button :size="size" type="success" @click="excelUpload"
+          >Excel表导入学员</el-button
+        >
+      </template>
+    </div>
+    <div class="bodyS">
+      <el-table
+        border
+        :data="tableData"
+        style="width: 100%"
+        :height="heightData"
+        ><el-table-column type="index" width="55" label="序号" align="center">
+        </el-table-column>
+        <el-table-column
+          align="center"
+          v-for="(item, index) in tableSet"
+          :key="index"
+          :prop="item.prop"
+          :label="item.label"
+          :width="item.width"
+        >
+          <template slot-scope="scope">
+            <div v-if="item.scope === 'sujectList'" class="rowSty">
+              <ul class="ulSty">
+                <li
+                  v-for="(items, indexs) in scope.row[item.prop]"
+                  :key="indexs"
+                >
+                  {{ changeSujectName(items) }}
+                </li>
+              </ul>
+              <span class="spanSty"
+                ><el-button type="text" @click="getSuject(scope.row)"
+                  >编辑</el-button
+                ></span
+              >
+            </div>
+            <div v-else-if="item.scope === 'set'">
+              <el-button type="text" @click="delStudent(scope.$index)"
+                >删除</el-button
+              >
+            </div>
+            <span v-else>{{ scope.row[item.prop] }}</span>
+          </template>
+        </el-table-column>
+      </el-table>
+    </div>
+    <div class="footS">
+      <el-button :size="size" @click="backPage">取消</el-button>
+      <el-button :size="size" @click="next" type="primary"
+        >确定,下一步</el-button
+      >
+    </div>
+    <add-student ref="addStudent" />
+    <suject-box ref="sujectBox" />
+    <upload-student ref="uploadStudent" />
+  </div>
+</template>
+
+<script>
+import sujectBox from "./sujectBox.vue";
+import addStudent from "./addStudent.vue";
+import uploadStudent from "./uploadStudent.vue";
+import { mapGetters } from "vuex";
+export default {
+  components: { addStudent, sujectBox, uploadStudent },
+  data() {
+    return {
+      size: "small",
+      typeList: [
+        { label: "视频商品", value: 1 },
+        { label: "题库商品", value: 2 },
+        { label: "补考商品", value: 3 },
+        { label: "前培商品", value: 4 },
+      ],
+      topData: {
+        type: [],
+        educationId: "",
+        businessId: "",
+        configId: "",
+      },
+      newBusinessLevel: [],
+      configList: [],
+      tableData: [],
+      heightData: 0,
+      tableSet: [
+        {
+          label: "学员编码",
+          prop: "studentCode",
+        },
+        {
+          label: "手机号码",
+          prop: "telphone",
+          width: "140px",
+        },
+        {
+          label: "学员姓名",
+          prop: "realname",
+        },
+        {
+          label: "学员身份证",
+          prop: "idCard",
+        },
+        {
+          label: "科目",
+          prop: "subjectIds",
+          scope: "sujectList",
+        },
+        {
+          label: "操作",
+          scope: "set",
+          width: "100px",
+        },
+      ],
+      sujectList: [],
+    };
+  },
+  watch: {
+    "topData.educationId"(newVal, oldVal) {
+      /**
+       * 选择教育类型检索出业务层级
+       */
+      this.topData.businessId = "";
+      this.$api
+        .inquirebusinessList({ status: 1, educationId: newVal })
+        .then((res) => {
+          this.newBusinessLevel = res.rows;
+        });
+    },
+    "topData.businessId"(newVal, oldVal) {
+      this.topData.type = [];
+      this.topData.configId = "";
+    },
+  },
+  computed: { ...mapGetters(["educationType"]) },
+  mounted() {
+    this.getHeightData();
+    this.getSujectList();
+  },
+  methods: {
+    /**
+     * 下一步
+     */
+    next() {
+      if (!this.tableData.length) {
+        this.$message.warning("请添加学员");
+        return;
+      }
+      if (!this.topData.configId || !this.topData.type.length) {
+        this.$message.warning("请选择配置及商品类型");
+        return;
+      }
+      let obj = {
+        topData: this.topData,
+        tableData: this.tableData,
+      };
+      this.$parent.changePage("second", obj);
+    },
+    /**
+     * 更新数据
+     */
+    uploadList(arr) {
+      let ays = JSON.parse(JSON.stringify(arr));
+      ays.forEach((item) => {
+        item.subjectIds = item.subjectIds.split(",").map(Number);
+      });
+      let newObjs = this.tableData.concat(ays);
+      this.tableData = this.$methodsTools.uniqueFunc(newObjs, "userId");
+    },
+    /**
+     * 导入
+     */
+    excelUpload() {
+      this.$refs.uploadStudent.openBox();
+    },
+    /**
+     * 转换科目Id为名称
+     */
+    changeSujectName(id) {
+      var names = "";
+      for (var i = 0; i < this.sujectList.length; i++) {
+        if (this.sujectList[i].id == id) {
+          names = this.sujectList[i].subjectName;
+          break;
+        }
+      }
+      return names;
+    },
+    /**
+     * 获取科目列表
+     */
+    getSujectList() {
+      this.$api
+        .inquireCourseSubject({
+          status: 1,
+        })
+        .then((res) => {
+          this.sujectList = res.rows;
+        });
+    },
+    /**
+     * 科目确定后返回数据
+     */
+    backObj(obj) {
+      for (let i = 0; i < this.tableData.length; i++) {
+        if (this.tableData[i].userId == obj.userId) {
+          this.$set(this.tableData[i], "subjectIds", obj.subjectIds);
+          break;
+        }
+      }
+    },
+    /**
+     * 编辑科目
+     */
+    getSuject(row) {
+      let obj = {
+        userId: row.userId,
+        subjectIds: row.subjectIds,
+      };
+      this.$refs.sujectBox.openBox(this.topData.businessId, obj);
+    },
+    /**
+     * 获取表格初始高度
+     */
+    getHeightData() {
+      this.$nextTick(() => {
+        this.heightData =
+          document.getElementsByClassName("bodyS")[0].clientHeight;
+      });
+    },
+    /**
+     * 删除单个学员列表
+     */
+    delStudent(index) {
+      this.$alert(
+        "确定删除该学员?<br />内容删除后将无法恢复,请慎重考虑",
+        "提示",
+        {
+          dangerouslyUseHTMLString: true,
+        }
+      )
+        .then(() => {
+          this.tableData.splice(index, 1);
+          this.$message.success("删除成功");
+        })
+        .catch(() => {});
+    },
+    /**
+     * 接收返回数据合并学员
+     */
+    changeStudent(arr) {
+      this.tableData = this.tableData.concat(arr);
+    },
+    /**
+     * 添加学员
+     */
+    SELECTPEOPLE() {
+      this.$refs.addStudent.formData = {
+        pageSize: 10,
+        pageNum: 1,
+        idCards: "",
+        getOrderNum: 0,
+      };
+      this.$refs.addStudent.openBox();
+    },
+    /**
+     * 根据业务层次筛选出对用商品配置
+     */
+    changeBusinessLevel(val) {
+      this.$api
+        .inquireorderbusinessconfigList({
+          businessId: val,
+          status: 1,
+        })
+        .then((res) => {
+          this.configList = res.rows;
+        });
+    },
+    backPage() {
+      this.$store.dispatch("tagsView/delView", this.$route).then((res) => {
+        this.$router.push({
+          path: "offlineOrder",
+        });
+      });
+    },
+  },
+};
+</script>
+
+<style lang="less" scoped>
+#firstStep {
+  display: flex;
+  flex-direction: column;
+  height: 100%;
+  .topS {
+    flex-shrink: 0;
+    height: 34px;
+  }
+  .bodyS {
+    flex: 1;
+    margin: 10px 0px;
+    box-shadow: 0px 0px 8px 1px rgba(0, 0, 0, 0.2);
+  }
+  .footS {
+    flex-shrink: 0;
+    height: 34px;
+    text-align: center;
+  }
+}
+.rowSty {
+  display: flex;
+  .ulSty {
+  }
+  .spanSty {
+    width: 50px;
+    flex-shrink: 0;
+    color: blue;
+  }
+}
+</style>

+ 179 - 0
src/views/Marketing/order/offlineOrder/batchRecord/firstStep/sujectBox.vue

@@ -0,0 +1,179 @@
+<template>
+  <div id="sujectBox">
+    <el-dialog
+      @closed="loadingClose"
+      :visible.sync="dialogVisible"
+      width="460px"
+      :show-close="false"
+      :close-on-click-modal="false"
+    >
+      <div slot="title" class="hearders">
+        <div class="leftTitle">科目选择</div>
+        <div class="rightBoxs">
+          <img src="@/assets/images/Close@2x.png" alt="" @click="close" />
+        </div>
+      </div>
+      <div>
+        <ul class="ulStyBox">
+          <el-checkbox-group v-model="disCheckList">
+            <li
+              v-for="(item, index) in selectArr"
+              :key="index"
+              style="margin-bottom: 6px"
+            >
+              <el-checkbox :label="item.id">{{ item.subjectName }}</el-checkbox>
+            </li>
+          </el-checkbox-group>
+        </ul>
+      </div>
+      <span slot="footer" class="dialog-footer">
+        <el-button @click="close">取 消</el-button>
+        <el-button type="primary" :loading="disabledBtn" @click="submit"
+          >确 定</el-button
+        >
+      </span>
+    </el-dialog>
+  </div>
+</template>
+
+<script>
+import pagination from "@/components/pagination";
+export default {
+  components: { pagination },
+  data() {
+    return {
+      dialogVisible: false,
+      disabledBtn: false,
+      disCheckList: [],
+      selectArr: [], //当前多选框选中数据
+      newData: {},
+    };
+  },
+  methods: {
+    openBox(id, obj) {
+      this.newData = JSON.parse(JSON.stringify(obj));
+      this.disCheckList = this.newData.subjectIds || [];
+      this.$api
+        .inquireCourseSubject({ status: 1, businessId: id })
+        .then((res) => {
+          this.selectArr = res.rows;
+          this.dialogVisible = true;
+        });
+    },
+    loadingClose() {
+      this.disabledBtn = false;
+    },
+    close() {
+      this.dialogVisible = false;
+    },
+    submit() {
+      this.$parent.backObj({
+        userId: this.newData.userId,
+        subjectIds: this.disCheckList,
+      });
+      this.close();
+    },
+  },
+};
+</script>
+
+<style lang="less" scoped>
+/deep/.el-button {
+  border-radius: 8px;
+}
+/deep/.el-dialog {
+  border-radius: 8px;
+  .el-dialog__header {
+    padding: 0;
+    .hearders {
+      height: 40px;
+      display: flex;
+      align-items: center;
+      justify-content: space-between;
+      padding: 0px 18px 0px 20px;
+      border-bottom: 1px solid #e2e2e2;
+      .leftTitle {
+        font-size: 14px;
+        font-weight: bold;
+        color: #2f4378;
+      }
+      .rightBoxs {
+        display: flex;
+        align-items: center;
+        img {
+          width: 14px;
+          height: 14px;
+          margin-left: 13px;
+          cursor: pointer;
+        }
+      }
+    }
+  }
+  .el-dialog__body {
+    padding: 0px 10px;
+  }
+  .el-dialog__footer {
+    padding: 0;
+    .dialog-footer {
+      padding: 0px 40px;
+      height: 70px;
+      border-top: 1px solid #e2e2e2;
+      display: flex;
+      align-items: center;
+      justify-content: flex-end;
+    }
+  }
+}
+.imgBox {
+  width: 100%;
+  // height: 210px;
+  border: 1px solid #e2e2e2;
+  border-radius: 8px;
+  padding: 8px 8px 3px;
+  display: flex;
+  flex-direction: column;
+  align-items: center;
+  .imgLabel {
+    flex: 1;
+    width: 100%;
+    border: 1px dotted #e2e2e2;
+    color: #999;
+    font-size: 14px;
+    cursor: pointer;
+    border-radius: 8px;
+    .msPhoto {
+      display: flex;
+      justify-content: center;
+      align-items: center;
+      max-width: 100%;
+      max-height: 270px;
+      img {
+        max-width: 100%;
+        max-height: 270px;
+      }
+    }
+    .imgbbx {
+      display: flex;
+      flex-direction: column;
+      align-items: center;
+      justify-content: center;
+      width: 100%;
+      height: 100%;
+      i {
+        font-weight: bold;
+        margin: 14px 0;
+        font-size: 24px;
+      }
+    }
+  }
+  p {
+    margin: 5px 0px;
+  }
+}
+.ulStyBox {
+  max-height: 230px;
+  overflow: auto;
+  background-color: #eee;
+  padding: 10px;
+}
+</style>

+ 398 - 0
src/views/Marketing/order/offlineOrder/batchRecord/firstStep/uploadStudent.vue

@@ -0,0 +1,398 @@
+<template>
+  <div id="uploadStudent">
+    <el-dialog
+      @closed="loadingClose"
+      :visible.sync="dialogVisible"
+      width="760px"
+      :show-close="false"
+      :close-on-click-modal="false"
+    >
+      <div slot="title" class="hearders">
+        <div class="leftTitle">Excel表导入学员</div>
+        <div class="rightBoxs">
+          <img src="@/assets/images/Close@2x.png" alt="" @click="close" />
+        </div>
+      </div>
+      <div>
+        <el-row :gutter="10">
+          <el-col :span="12" style="border-right: 1px solid #000">
+            <h4>重要说明:</h4>
+            <ul>
+              <li>1.请按照Excel模板进行学员名单整理,方可正常上传</li>
+              <li>(1)手机号码格式正确</li>
+              <li>(2)手机号码+身份证号码,两者关联是唯一</li>
+              <li>(3)科目内容,用英式半角“,”隔开</li>
+              <li>2.学员库没有的新数据,请确保:</li>
+              <li>(1)手机号码格式正确</li>
+              <li>(2)手机号码+身份证号码,两者关联是唯一</li>
+              <li>(3)导入成功后,会为新学员立马注册账号</li>
+            </ul>
+          </el-col>
+          <el-col :span="12">
+            <div style="margin: 0px 0px 12px 14px">
+              <el-link type="primary" @click="getDowm">下载模板</el-link>
+            </div>
+            <label
+              for="mobles"
+              class="el-button el-button--primary"
+              style="margin-left: 14px; padding: 10px 20px"
+              >上传学员名单</label
+            ><input
+              style="display: none"
+              type="file"
+              id="mobles"
+              ref="input1"
+              @change="importMobleadd"
+            />
+            <div style="padding: 20px" v-if="importNo">
+              <div>
+                成功:<span style="color: green; font-weight: bold">{{
+                  successList.length
+                }}</span>
+                条
+              </div>
+              <div style="margin-top: 14px">
+                失败:<span style="color: red; font-weight: bold"
+                  >{{ errorList.length }} </span
+                >条
+              </div>
+              <el-button
+                style="margin-top: 10px"
+                size="small"
+                type="warning"
+                @click="openInfo"
+                >查看详情</el-button
+              >
+            </div>
+          </el-col>
+        </el-row>
+      </div>
+      <span slot="footer" class="dialog-footer">
+        <el-button @click="close">取 消</el-button>
+      </span>
+    </el-dialog>
+    <el-dialog
+      :visible.sync="diaUpload"
+      width="960px"
+      :show-close="false"
+      :close-on-click-modal="false"
+    >
+      <div slot="title" class="hearders">
+        <div class="leftTitle">导入详情</div>
+        <div class="rightBoxs">
+          <img
+            src="@/assets/images/Close@2x.png"
+            alt=""
+            @click="diaUpload = false"
+          />
+        </div>
+      </div>
+      <div>
+        <div class="disSty">
+          <div>
+            <el-badge
+              :value="successList.length ? successList.length : ''"
+              class="item"
+              style="margin-right: 20px"
+            >
+              <el-button
+                size="small"
+                :type="activeIndex === 1 ? 'primary' : ''"
+                @click="changeIndex(1)"
+                >成功信息</el-button
+              >
+            </el-badge>
+            <el-badge
+              :value="errorList.length ? errorList.length : ''"
+              class="item"
+            >
+              <el-button
+                size="small"
+                :type="activeIndex === 2 ? 'primary' : ''"
+                @click="changeIndex(2)"
+                >失败信息</el-button
+              >
+            </el-badge>
+          </div>
+          <el-button
+            v-if="errorList.length"
+            size="small"
+            type="warning"
+            @click="dowmError"
+            >下载失败Excel</el-button
+          >
+        </div>
+        <div>
+          <el-table border :data="tableData" style="width: 100%">
+            <el-table-column
+              align="center"
+              v-for="(item, index) in comTypes(tableSet)"
+              :key="index"
+              :prop="item.prop"
+              :label="item.label"
+              :width="item.width"
+            >
+              <template slot-scope="scope">
+                <span>{{ scope.row[item.prop] }}</span>
+              </template>
+            </el-table-column>
+          </el-table>
+        </div>
+      </div>
+      <span slot="footer" class="dialog-footer">
+        <el-button @click="diaUpload = false">取 消</el-button>
+      </span>
+    </el-dialog>
+  </div>
+</template>
+
+<script>
+import * as baseUrls from "@/utils/request.js";
+export default {
+  data() {
+    return {
+      dialogVisible: false,
+      disabledBtn: false,
+      errorList: [],
+      successList: [],
+      importNo: "",
+      diaUpload: false,
+      tableData: [],
+      activeIndex: 1,
+      tableSet: [
+        {
+          label: "学员编码",
+          prop: "studentCode",
+          type: "success",
+        },
+        {
+          label: "学员姓名",
+          prop: "realname",
+        },
+        {
+          label: "学员身份证",
+          prop: "idCard",
+        },
+        {
+          label: "绑定手机号码",
+          prop: "telphone",
+        },
+        {
+          label: "失败原因",
+          prop: "cause",
+          type: "error",
+        },
+      ],
+    };
+  },
+  computed: {
+    comTypes: function () {
+      return function (list) {
+        let arr = [];
+        if (this.activeIndex === 1) {
+          arr = list.filter((item) => {
+            return item.type != "error";
+          });
+        }
+        if (this.activeIndex === 2) {
+          arr = list.filter((item) => {
+            return item.type != "success";
+          });
+        }
+        return arr;
+      };
+    },
+  },
+  methods: {
+    /**
+     * 切换成功失败数据表格
+     */
+    changeIndex(int) {
+      if (int === this.activeIndex) return;
+      this.activeIndex = int;
+      if (int === 1) {
+        this.$nextTick(() => {
+          this.tableData = this.successList;
+        });
+      }
+      if (int === 2) {
+        this.$nextTick(() => {
+          this.tableData = this.errorList;
+        });
+      }
+    },
+    /**
+     * 打开详情
+     */
+    openInfo() {
+      this.activeIndex = 1;
+      this.tableData = this.successList;
+      this.diaUpload = true;
+    },
+    /**
+     * 下载模板
+     */
+    getDowm() {
+      let url =
+        baseUrls.BASE_IMG_URL +
+        "oss/images/file/20220406/1649231575429.xlsx" +
+        `?time=${this.$methodsTools.getNewTime()}`;
+      let link = document.createElement("a");
+      let fileName = "导入模板" + ".xlsx";
+      document.body.appendChild(link);
+      link.href = url;
+      link.dowmload = fileName;
+      link.click();
+      link.remove();
+    },
+    /**
+     * 导入
+     */
+    importMobleadd(e) {
+      var self = this;
+      var file = e.target.files[0];
+      let formData = new FormData();
+      formData.append("file", file);
+      formData.append("importNo", this.importNo);
+      this.$api
+        .appuserimportData(formData)
+        .then((res) => {
+          this.errorList = res.data.errorList;
+          this.successList = res.data.successList;
+          this.importNo = res.data.importNo;
+          this.$message.success("上传成功");
+          if (res.data.successList.length) {
+            this.$parent.uploadList(res.data.successList);
+          }
+        })
+        .finally(() => {
+          e.target.value = "";
+        });
+    },
+    /**
+     * 下载失败数据
+     */
+    dowmError() {
+      this.$api.appuserimporexportFailData(this.errorList).then((res) => {
+        let url = baseUrls.baseURL + "common/download?fileName=" + res.msg;
+        let link = document.createElement("a");
+        let fileName = "导出错误Excel" + ".xlsx";
+        document.body.appendChild(link);
+        link.href = url;
+        link.dowmload = fileName;
+        link.click();
+        link.remove();
+      });
+    },
+    loadingClose() {
+      this.disabledBtn = false;
+    },
+    close() {
+      this.dialogVisible = false;
+    },
+    openBox() {
+      this.errorList = [];
+      this.successList = [];
+      this.importNo = "";
+      this.dialogVisible = true;
+    },
+  },
+};
+</script>
+
+<style lang="less" scoped>
+.disSty {
+  margin-bottom: 10px;
+  display: flex;
+  justify-content: space-between;
+}
+/deep/.el-button {
+  border-radius: 8px;
+}
+/deep/.el-dialog {
+  border-radius: 8px;
+  .el-dialog__header {
+    padding: 0;
+    .hearders {
+      height: 40px;
+      display: flex;
+      align-items: center;
+      justify-content: space-between;
+      padding: 0px 18px 0px 20px;
+      border-bottom: 1px solid #e2e2e2;
+      .leftTitle {
+        font-size: 14px;
+        font-weight: bold;
+        color: #2f4378;
+      }
+      .rightBoxs {
+        display: flex;
+        align-items: center;
+        img {
+          width: 14px;
+          height: 14px;
+          margin-left: 13px;
+          cursor: pointer;
+        }
+      }
+    }
+  }
+  .el-dialog__footer {
+    padding: 0;
+    .dialog-footer {
+      padding: 0px 40px;
+      height: 70px;
+      border-top: 1px solid #e2e2e2;
+      display: flex;
+      align-items: center;
+      justify-content: flex-end;
+    }
+  }
+}
+.imgBox {
+  width: 100%;
+  // height: 210px;
+  border: 1px solid #e2e2e2;
+  border-radius: 8px;
+  padding: 8px 8px 3px;
+  display: flex;
+  flex-direction: column;
+  align-items: center;
+  .imgLabel {
+    flex: 1;
+    width: 100%;
+    border: 1px dotted #e2e2e2;
+    color: #999;
+    font-size: 14px;
+    cursor: pointer;
+    border-radius: 8px;
+    .msPhoto {
+      display: flex;
+      justify-content: center;
+      align-items: center;
+      max-width: 100%;
+      max-height: 270px;
+      img {
+        max-width: 100%;
+        max-height: 270px;
+      }
+    }
+    .imgbbx {
+      display: flex;
+      flex-direction: column;
+      align-items: center;
+      justify-content: center;
+      width: 100%;
+      height: 100%;
+      i {
+        font-weight: bold;
+        margin: 14px 0;
+        font-size: 24px;
+      }
+    }
+  }
+  p {
+    margin: 5px 0px;
+  }
+}
+</style>

+ 65 - 0
src/views/Marketing/order/offlineOrder/batchRecord/index.vue

@@ -0,0 +1,65 @@
+<template>
+  <div id="batchRecord">
+    <el-tabs v-model="activeName" :before-leave="beforeLeave">
+      <el-tab-pane
+        label="选择商品类型层次"
+        name="first"
+        :disabled="activeName !== 'first'"
+      ></el-tab-pane>
+      <el-tab-pane
+        label="设置商品"
+        name="second"
+        :disabled="activeName !== 'second'"
+      ></el-tab-pane>
+      <el-tab-pane
+        label="下单结果"
+        name="third"
+        :disabled="activeName !== 'third'"
+      ></el-tab-pane>
+    </el-tabs>
+    <div class="box-height">
+      <first-step v-show="activeName === 'first'" />
+      <second-step v-show="activeName === 'second'" ref="secondStep" />
+      <third-step v-show="activeName === 'third'" />
+    </div>
+  </div>
+</template>
+
+<script>
+import firstStep from "./firstStep/index.vue";
+import secondStep from "./secondStep/index.vue";
+import thirdStep from "./thirdStep/index.vue";
+export default {
+    name:"BatchRecord",
+  components: { firstStep, secondStep, thirdStep },
+  data() {
+    return {
+      activeName: "first",
+    };
+  },
+  methods: {
+    beforeLeave(activeName, oldActiveName) {
+      if (activeName === oldActiveName) {
+        return false;
+      } else {
+        return true;
+      }
+    },
+    changePage(name,obj){
+        this.$refs.secondStep.getInitData(obj)
+        this.activeName = name
+    }
+  },
+};
+</script>
+
+<style lang="less" scoped>
+#batchRecord {
+  display: flex;
+  flex-direction: column;
+  height: calc(100vh - 126px);
+}
+.box-height {
+  height: calc(100% - 55px);
+}
+</style>

+ 241 - 0
src/views/Marketing/order/offlineOrder/batchRecord/secondStep/index.vue

@@ -0,0 +1,241 @@
+<template>
+  <div id="secondStep">
+    <el-table
+      :data="tableData"
+      :span-method="objectSpanMethod"
+      border
+      style="width: 100%; margin-top: 10px"
+    >
+      <el-table-column
+        align="center"
+        v-for="(item, index) in tableSet"
+        :key="index"
+        :prop="item.prop"
+        :label="item.label"
+        ><template slot-scope="scope">
+          <span>{{ scope.row[item.prop] }}</span>
+        </template>
+      </el-table-column>
+    </el-table>
+  </div>
+</template>
+
+<script>
+export default {
+  data() {
+    return {
+      tableSet: [
+        {
+          label: "学员姓名",
+          prop: "realname",
+        },
+        {
+          label: "学员身份证",
+          prop: "idCard",
+        },
+        {
+          label: "手机号码",
+          prop: "telphone",
+        },
+        {
+          label: "科目",
+          prop: "subjectIds",
+        },
+        {
+          label: "所选商品",
+          prop: "goodsName",
+        },
+        {
+          label: "商品标准价格",
+          prop: "standPrice",
+        },
+        {
+          label: "商品成交价",
+          prop: "subjectIds",
+        },
+        {
+          label: "本次收费金额",
+          prop: "subjectIds",
+        },
+      ],
+      tableData: [],
+      typeNameArr: [], // 第一列进行合并操作时存放的数组变量
+      typeNamePos: 0, // 上面的数组的下标值
+      storeArr: [], // 第二列进行合并操作时存放的数组变量
+      storePos: 0, // 上面的数组的下标值
+      feeArr: [], // 第三列进行合并操作时存放的数组变量
+      feePos: 0, // 上面的数组的下标值
+      fourArr: [], // 第三列进行合并操作时存放的数组变量
+      fourPos: 0, // 上面的数组的下标值
+    };
+  },
+  mounted() {},
+  methods: {
+    merageInit() {
+      // 在下文的时候会用到,对数据进行初始化是很有必要的
+      this.typeNameArr = [];
+      this.typeNamePos = 0;
+      this.storeArr = [];
+      this.storePos = 0;
+      this.feeArr = [];
+      this.feePos = 0;
+      this.fourArr = [];
+      this.fourPos = 0;
+    },
+    merage() {
+      this.merageInit(); // 前文的初始化数据函数
+      for (let i = 0; i < this.tableData.length; i += 1) {
+        console.log(this.tableData[i], "aa");
+        if (i === 0) {
+          // 第一行必须存在
+          this.typeNameArr.push(1);
+          this.typeNamePos = 0;
+          this.storeArr.push(1);
+          this.storePos = 0;
+          this.feeArr.push(1);
+          this.feePos = 0;
+          this.fourArr.push(1);
+          this.fourPos = 0;
+        } else {
+          // 判断当前元素与上一个元素是否相同,eg:this.typeNamePos 是 this.typeNameArr序号
+          // 第一列 下面的是eslint的不限制语法
+          // eslint-disable-next-line no-lonely-if
+          if (this.tableData[i].realname === this.tableData[i - 1].realname) {
+            this.typeNameArr[this.typeNamePos] += 1;
+            this.typeNameArr.push(0);
+          } else {
+            this.typeNameArr.push(1);
+            this.typeNamePos = i;
+          }
+          // 第二列
+          if (
+            this.tableData[i].idCard === this.tableData[i - 1].idCard &&
+            this.tableData[i].realname === this.tableData[i - 1].realname
+          ) {
+            this.storeArr[this.storePos] += 1;
+            this.storeArr.push(0);
+          } else {
+            this.storeArr.push(1);
+            this.storePos = i;
+          }
+          // 第三列
+          if (
+            this.tableData[i].telphone === this.tableData[i - 1].telphone &&
+            this.tableData[i].idCard === this.tableData[i - 1].idCard &&
+            this.tableData[i].realname === this.tableData[i - 1].realname
+          ) {
+            this.feeArr[this.feePos] += 1;
+            this.feeArr.push(0);
+          } else {
+            this.feeArr.push(1);
+            this.feePos = i;
+          }
+          // 第四列
+          if (
+            this.tableData[i].telphone === this.tableData[i - 1].telphone &&
+            this.tableData[i].idCard === this.tableData[i - 1].idCard &&
+            this.tableData[i].realname === this.tableData[i - 1].realname &&
+            this.tableData[i].subjectId === this.tableData[i - 1].subjectId
+          ) {
+            this.fourArr[this.fourPos] += 1;
+            this.fourArr.push(0);
+          } else {
+            this.fourArr.push(1);
+            this.fourPos = i;
+          }
+        }
+      }
+    },
+    objectSpanMethod({ row, column, rowIndex, columnIndex }) {
+      if (columnIndex === 0) {
+        // 第一列的合并方法
+        const row1 = this.typeNameArr[rowIndex];
+        const col1 = row1 > 0 ? 1 : 0; // 如果被合并了row = 0; 则他这个列需要取消
+        return {
+          rowspan: row1,
+          colspan: col1,
+        };
+      } else if (columnIndex === 1) {
+        // 第二列的合并方法
+        const row2 = this.storeArr[rowIndex];
+        const col2 = row2 > 0 ? 1 : 0; // 如果被合并了row = 0; 则他这个列需要取消
+        return {
+          rowspan: row2,
+          colspan: col2,
+        };
+      } else if (columnIndex === 2) {
+        // 第三列的合并方法
+        const row3 = this.feeArr[rowIndex];
+        const col3 = row3 > 0 ? 1 : 0; // 如果被合并了row = 0; 则他这个列需要取消
+        return {
+          rowspan: row3,
+          colspan: col3,
+        };
+      } else if (columnIndex === 3) {
+        // 第四列的合并方法
+        const row4 = this.fourArr[rowIndex];
+        const col4 = row4 > 0 ? 1 : 0; // 如果被合并了row = 0; 则他这个列需要取消
+        return {
+          rowspan: row4,
+          colspan: col4,
+        };
+      }
+    },
+    getInitData(obj) {
+      let data = JSON.parse(JSON.stringify(obj.tableData));
+      this.$api
+        .inquireorderconfiggoodsList({
+          configId: obj.topData.configId,
+        })
+        .then((res) => {
+          data.forEach((item) => {
+            item.subjectList = [];
+            if (item.subjectIds && item.subjectIds.length) {
+              for (let i = 0; i < item.subjectIds.length; i++) {
+                for (let j = 0; j < res.rows.length; j++) {
+                  if (res.rows[j].subjectId == item.subjectIds[i]) {
+                    var ary = JSON.parse(JSON.stringify(res.rows[j].goodsList));
+                    var datas = ary.map((items) => {
+                      if (obj.topData.type.indexOf(items.goodsType) !== -1) {
+                        items.checked = true;
+                      } else {
+                        items.checked = false;
+                      }
+                      return items;
+                    });
+                    item.subjectList.push({
+                      subjectId: item.subjectIds[i],
+                      goodsList: datas,
+                    });
+                  }
+                }
+              }
+            }
+          });
+          this.decomposeFunc(data);
+        });
+    },
+    decomposeFunc(obj) {
+      var arrays = [];
+      obj.forEach((item) => {
+        if (item.subjectList.length == 0) {
+          arrays.push(item);
+        } else {
+          item.subjectList.forEach((items) => {
+            items.goodsList.forEach((itemsxs) => {
+              itemsxs.subjectId = items.subjectId;
+              var datas = Object.assign({ ...item, ...itemsxs });
+              arrays.push(datas);
+            });
+          });
+        }
+      });
+      this.tableData = arrays;
+      this.merage();
+    },
+  },
+};
+</script>
+
+<style lang="less" scoped>
+</style>

+ 15 - 0
src/views/Marketing/order/offlineOrder/batchRecord/thirdStep/index.vue

@@ -0,0 +1,15 @@
+<template>
+  <div id="thirdStep">thirdStep</div>
+</template>
+
+<script>
+export default {
+  data() {
+    return {};
+  },
+  methods: {},
+};
+</script>
+
+<style lang="less" scoped>
+</style>

+ 368 - 46
src/views/Marketing/order/offlineOrder/goodsMatch/matchInfoData.vue

@@ -12,7 +12,6 @@
     </div>
     <el-table border :data="tableData" style="width: 100%; margin-top: 16px">
       <el-table-column
-        align="center"
         v-for="(item, index) in tableSet"
         :key="index"
         :prop="item.prop"
@@ -21,8 +20,15 @@
       >
         <template slot-scope="scope">
           <ul v-if="item.scope === 'list'">
-            <li v-for="(items, indexs) in scope.row[item.prop]" :key="indexs">
-              {{ items.goodsName }}({{ items.majob }})
+            <li
+              v-for="(items, indexs) in comList(
+                scope.row[item.prop],
+                item.goodsType
+              )"
+              :key="indexs"
+            >
+              {{ items.goodsName }}
+              <span v-if="items.categoryName">({{ items.categoryName }})</span>
             </li>
           </ul>
           <span v-else>{{ scope.row[item.prop] }}</span>
@@ -34,6 +40,95 @@
         </template>
       </el-table-column>
     </el-table>
+    <el-dialog
+      :visible.sync="disBoxs"
+      width="660px"
+      :show-close="false"
+      :close-on-click-modal="false"
+    >
+      <div slot="title" class="hearders">
+        <div class="leftTitle">
+          {{ newData.subjectName }} - 设置默认匹配商品
+        </div>
+        <div class="rightBoxs">
+          <img
+            src="@/assets/images/Close@2x.png"
+            alt=""
+            @click="disBoxs = false"
+          />
+        </div>
+      </div>
+      <el-row :gutter="10">
+        <el-col :span="4">
+          <ul>
+            <li
+              v-for="(item, index) in goodsType"
+              :key="index"
+              class="liSty"
+              :style="activeType === item.value ? 'color:red;' : ''"
+              @click="searchGoods(item.value)"
+            >
+              {{ item.label }}
+            </li>
+          </ul>
+        </el-col>
+        <el-col :span="20">
+          <div>
+            <el-input
+              :size="size"
+              v-model="goodsName"
+              style="width: 190px"
+              placeholder="请输入商品名称"
+            ></el-input>
+            <el-input
+              :size="size"
+              v-model="goodsPrice"
+              style="width: 190px"
+              placeholder="请输入商品标准价格"
+            ></el-input>
+            <el-button
+              :size="size"
+              style="margin-left: 10px"
+              type="primary"
+              @click="getSeachData(activeType)"
+              >查询</el-button
+            >
+            <el-button :size="size" @click="init">重置</el-button>
+          </div>
+          <div
+            style="margin-top: 14px; text-align: center"
+            v-if="!goodsList.length"
+          >
+            暂无符合条件商品
+          </div>
+          <el-checkbox-group v-model="checkList">
+            <ul
+              style="
+                max-height: 240px;
+                overflow: auto;
+                background: #eee;
+                margin-top: 10px;
+              "
+            >
+              <li
+                v-for="(item, index) in goodsList"
+                :key="index"
+                style="padding: 10px; font-size: 13px"
+              >
+                <el-checkbox :label="item.goodsId">
+                  {{ item.code }} - {{ item.goodsName }} -
+                  <span style="color: red">¥{{ item.standPrice }}</span>
+                </el-checkbox>
+              </li>
+            </ul>
+          </el-checkbox-group>
+        </el-col>
+      </el-row>
+      <span slot="footer" class="dialog-footer">
+        <el-button @click="disBoxs = false">取 消</el-button>
+        <el-button @click="submitForms">确 定</el-button>
+      </span>
+    </el-dialog>
   </div>
 </template>
 
@@ -42,38 +137,10 @@ export default {
   name: "MatchInfoData",
   data() {
     return {
+      size: "mini",
       queryData: {},
       businessData: {},
-      tableData: [
-        {
-          subjectId: 1,
-          subjectName: "科目一",
-          videoGoods: [
-            {
-              goodsName: "商品一",
-              majob: "专业",
-            },
-          ],
-          bankGoods: [
-            {
-              goodsName: "商品二",
-              majob: "专业",
-            },
-          ],
-          bukaoGoods: [
-            {
-              goodsName: "商品三",
-              majob: "专业",
-            },
-          ],
-          qianpeiGoods: [
-            {
-              goodsName: "商品四",
-              majob: "专业",
-            },
-          ],
-        },
-      ],
+      tableData: [],
       tableSet: [
         {
           label: "科目",
@@ -81,25 +148,55 @@ export default {
         },
         {
           label: "视频-默认匹配商品",
-          prop: "videoGoods",
+          prop: "goodsList",
           scope: "list",
+          goodsType: 1,
         },
         {
           label: "题库-默认匹配商品",
-          prop: "bankGoods",
+          prop: "goodsList",
           scope: "list",
+          goodsType: 2,
         },
         {
           label: "补考-默认匹配商品",
-          prop: "bukaoGoods",
+          prop: "goodsList",
           scope: "list",
+          goodsType: 3,
         },
         {
           label: "前培-默认匹配商品",
-          prop: "qianpeiGoods",
+          prop: "goodsList",
           scope: "list",
+          goodsType: 4,
+        },
+      ],
+      disBoxs: false,
+      goodsType: [
+        {
+          label: "视频商品",
+          value: 1,
+        },
+        {
+          label: "题库商品",
+          value: 2,
+        },
+        {
+          label: "补考商品",
+          value: 3,
+        },
+        {
+          label: "前培商品",
+          value: 4,
         },
       ],
+      activeType: "",
+      goodsName: "",
+      goodsPrice: "",
+      newData: {},
+      goodsList: [],
+      checkList: [],
+      statusPop: "", //1新增2修改
     };
   },
   created() {
@@ -108,7 +205,112 @@ export default {
   mounted() {
     this.initData();
   },
+  computed: {
+    comList: function () {
+      return function (v, int) {
+        let arr = [];
+        v.forEach((item) => {
+          if (item.goodsType == int) {
+            arr.push(item);
+          }
+        });
+        return arr;
+      };
+    },
+  },
+  watch: {
+    activeType(val, oldVal) {
+      if (!val) return;
+      this.getSeachData(val);
+    },
+  },
   methods: {
+    init() {
+      this.goodsName = "";
+      this.goodsPrice = "";
+      this.getSeachData(this.activeType);
+    },
+    /**
+     * 搜索弹窗内容
+     */
+    getSeachData(type) {
+      var priceReg = /(^[1-9]\d*(\.\d{1,2})?$)|(^0(\.\d{1,2})?$)/;
+      if (this.goodsPrice && !priceReg.test(this.goodsPrice)) {
+        this.$message.warning("请输入正确价格");
+        return;
+      }
+      var data = {
+        goodsType: type,
+        goodsName: this.goodsName || "",
+        standPrice: this.goodsPrice || "",
+      };
+      if (type == 1 || type == 2) {
+        data.subjectId = this.newData.subjectId;
+      }
+      if (type == 3 || type == 4) {
+        data.businessIds = this.businessData.id;
+      }
+      this.$api.inquireGoods(data).then((res) => {
+        this.goodsList = res.rows;
+      });
+    },
+    /**
+     * 设置
+     */
+    setOption(v) {
+      this.newData = JSON.parse(JSON.stringify(v));
+      this.checkList = v.goodsList.map((item) => {
+        return item.goodsId;
+      });
+      if (this.checkList.length) {
+        this.statusPop = 2;
+      } else {
+        this.statusPop = 1;
+      }
+      this.activeType = 1;
+      this.goodsNameOrPrice = "";
+      this.disBoxs = true;
+    },
+    searchGoods(int) {
+      this.activeType = int;
+    },
+    submitForms() {
+      if (this.statusPop === 1) {
+        if (!this.checkList.length) {
+          this.$message.warning("请选择匹配商品");
+          return;
+        }
+        //新增
+        this.$api
+          .apporderconfiggoods({
+            configId: this.queryData.id,
+            subjectId: this.newData.subjectId,
+            status: 1,
+            goodsIds: this.checkList.toString(),
+          })
+          .then((res) => {
+            this.$message.success("提交成功");
+            this.initData(true);
+            this.disBoxs = false;
+          });
+      }
+      if (this.statusPop === 2) {
+        //修改
+        this.$api
+          .editorderconfiggoods({
+            configId: this.queryData.id,
+            id: this.newData.id,
+            subjectId: this.newData.subjectId,
+            status: this.checkList.length ? 1 : -1,
+            goodsIds: this.checkList.toString(),
+          })
+          .then((res) => {
+            this.$message.success("提交成功");
+            this.initData(true);
+            this.disBoxs = false;
+          });
+      }
+    },
     backConfig() {
       this.$store.dispatch("tagsView/delView", this.$route).then((res) => {
         this.$router.push({
@@ -116,24 +318,52 @@ export default {
         });
       });
     },
-    initData() {
+    initData(status) {
+      if (!status) {
+        this.$api
+          .obtainbusiness(Number(this.queryData.businessId))
+          .then((res) => {
+            this.businessData = res.data;
+          });
+      }
       this.$api
-        .obtainbusiness(Number(this.queryData.businessId))
+        .inquireCourseSubject({ businessId: Number(this.queryData.businessId) })
         .then((res) => {
-          this.businessData = res.data;
+          this.$api
+            .inquireorderconfiggoodsList({
+              configId: Number(this.queryData.id),
+            })
+            .then((result) => {
+              let arr = res.rows.map((item) => {
+                return {
+                  subjectId: item.id,
+                  subjectName: item.subjectName,
+                  goodsList: [],
+                };
+              });
+              result.rows.forEach((item) => {
+                0;
+                arr.forEach((items) => {
+                  if (items.subjectId == item.subjectId) {
+                    items.goodsList = item.goodsList;
+                    items.id = item.id;
+                  }
+                });
+              });
+              this.tableData = arr;
+            });
         });
-      this.$api
-        .inquireorderconfiggoodsList({
-          configId: Number(this.queryData.id),
-        })
-        .then((res) => {});
     },
-    setOption(v) {},
   },
 };
 </script>
 
 <style lang="less" scoped>
+.liSty {
+  padding: 8px 0px;
+  cursor: pointer;
+  text-align: center;
+}
 .topSty {
   display: inline-block;
   font-size: 14px;
@@ -141,4 +371,96 @@ export default {
   background: #eee;
   padding: 4px;
 }
+/deep/.el-button {
+  border-radius: 8px;
+}
+/deep/.el-dialog {
+  border-radius: 8px;
+  .el-dialog__header {
+    padding: 0;
+    .hearders {
+      height: 40px;
+      display: flex;
+      align-items: center;
+      justify-content: space-between;
+      padding: 0px 18px 0px 20px;
+      border-bottom: 1px solid #e2e2e2;
+      .leftTitle {
+        font-size: 14px;
+        font-weight: bold;
+        color: #2f4378;
+      }
+      .rightBoxs {
+        display: flex;
+        align-items: center;
+        img {
+          width: 14px;
+          height: 14px;
+          margin-left: 13px;
+          cursor: pointer;
+        }
+      }
+    }
+  }
+  .el-dialog__body {
+    padding: 10px 20px;
+  }
+  .el-dialog__footer {
+    padding: 0;
+    .dialog-footer {
+      padding: 0px 40px;
+      height: 70px;
+      border-top: 1px solid #e2e2e2;
+      display: flex;
+      align-items: center;
+      justify-content: flex-end;
+    }
+  }
+}
+.imgBox {
+  width: 100%;
+  // height: 210px;
+  border: 1px solid #e2e2e2;
+  border-radius: 8px;
+  padding: 8px 8px 3px;
+  display: flex;
+  flex-direction: column;
+  align-items: center;
+  .imgLabel {
+    flex: 1;
+    width: 100%;
+    border: 1px dotted #e2e2e2;
+    color: #999;
+    font-size: 14px;
+    cursor: pointer;
+    border-radius: 8px;
+    .msPhoto {
+      display: flex;
+      justify-content: center;
+      align-items: center;
+      max-width: 100%;
+      max-height: 270px;
+      img {
+        max-width: 100%;
+        max-height: 270px;
+      }
+    }
+    .imgbbx {
+      display: flex;
+      flex-direction: column;
+      align-items: center;
+      justify-content: center;
+      width: 100%;
+      height: 100%;
+      i {
+        font-weight: bold;
+        margin: 14px 0;
+        font-size: 24px;
+      }
+    }
+  }
+  p {
+    margin: 5px 0px;
+  }
+}
 </style>

+ 11 - 2
src/views/Marketing/order/offlineOrder/index.vue

@@ -7,8 +7,10 @@
       :loading="loading"
     >
       <template slot="customize">
-        <el-button size="medium" type="primary" @click="setGoodsOptions"
+        <el-button size="medium" type="primary" @click="setGoodsOptions(1)"
           >设置商品默认匹配</el-button
+        ><el-button size="medium" type="primary" @click="setGoodsOptions(2)"
+          >批量录单</el-button
         >
       </template>
       <template slot="btn" slot-scope="props">
@@ -256,10 +258,17 @@ export default {
     this.search();
   },
   methods: {
-    setGoodsOptions() {
+    setGoodsOptions(int) {
+      if (int === 1) {
         this.$router.push({
           path: "goodsMatchToBusin",
         });
+      }
+      if (int === 2) {
+        this.$router.push({
+          path: "batchRecord",
+        });
+      }
     },
     loadingClose() {
       this.disabledBtn = false;