Browse Source

Merge branch 'dev0.3' into stage

cz 1 năm trước cách đây
mục cha
commit
93f115a5b1

BIN
src/assets/images/mail-preview.png


+ 7 - 1
src/views/connect/E-mail/mail/com/mailDetail.vue

@@ -112,7 +112,12 @@
         <div class="value">
           <div
             v-for="(item, index) in fileList"
-            style="margin-right: 20px; display: flex; align-items: center"
+            style="
+              margin-right: 20px;
+              display: flex;
+              align-items: center;
+              margin-bottom: 5px;
+            "
             :key="index"
           >
             <span style="cursor: pointer" @click="handleClickFile(item)">{{
@@ -591,6 +596,7 @@ defineExpose({
         font-weight: 700;
         margin-right: 10px;
         display: flex;
+        flex-wrap: wrap;
       }
     }
   }

+ 2 - 2
src/views/connect/E-mail/mail/com/mailList.vue

@@ -343,9 +343,9 @@ const handleRowClick = (row, index) => {
 };
 
 const init = () => {
-  getList();
+  // getList();
 };
-
+getList();
 const handleCurrentChange = (val) => {
   tableData.pagination.pageNum = val;
   getList();

+ 59 - 16
src/views/connect/E-mail/mail/com/mailWrite.vue

@@ -215,22 +215,45 @@
             style="width: 50%"
           />
         </el-form-item> -->
-        <el-form-item label="发件人" prop="replyTo">
-          <el-select
-            v-model="formData.data.replyTo"
-            filterable
-            placeholder="请选择"
-            style="width: 50%"
-            @change="handleChangeReply"
-          >
-            <el-option
-              v-for="item in userMailList"
-              :key="item.mailUser"
-              :label="item.mailUser"
-              :value="item.mailUser"
-            />
-          </el-select>
-        </el-form-item>
+
+        <el-row>
+          <el-col :span="6">
+            <el-form-item label="发件人" prop="replyTo">
+              <el-select
+                v-model="formData.data.replyTo"
+                filterable
+                placeholder="请选择"
+                style="width: 100%"
+                @change="handleChangeReply"
+              >
+                <el-option
+                  v-for="item in userMailList"
+                  :key="item.mailUser"
+                  :label="item.mailUser"
+                  :value="item.mailUser"
+                />
+              </el-select>
+            </el-form-item>
+          </el-col>
+          <el-col :span="6">
+            <el-form-item label="签  名:">
+              <el-select
+                v-model="formData.data.templateId"
+                filterable
+                placeholder="请选择"
+                style="width: 100%"
+                @change="handleChangeTemplate"
+              >
+                <el-option
+                  v-for="item in templateList"
+                  :key="item.id"
+                  :label="item.templateName"
+                  :value="item.id"
+                />
+              </el-select>
+            </el-form-item>
+          </el-col>
+        </el-row>
         <el-form-item>
           <el-button type="primary" @click="handleSend()"> 发 送 </el-button>
         </el-form-item>
@@ -639,6 +662,26 @@ watch(
     }
   }
 );
+const templateList = ref([]);
+const getTemplateList = () => {
+  proxy
+    .post("/mailSignature/page", {
+      pageNum: 1,
+      pageSize: 9999,
+    })
+    .then((res) => {
+      templateList.value = res.rows;
+    });
+};
+getTemplateList();
+const handleChangeTemplate = (val) => {
+  if (val) {
+    const current = templateList.value.find((x) => x.id === val);
+    contentEditor.value.changeHtml(
+      `${formData.data.content}<br><div style="width: 50%;padding: 15px;overflow: auto;box-shadow: 0px 0px 12px rgba(0, 0, 0, .12);">${current.content}</div>`
+    );
+  }
+};
 
 onMounted(() => {});
 

+ 324 - 0
src/views/connect/E-mail/signature/index.vue

@@ -0,0 +1,324 @@
+<template>
+  <div class="tenant">
+    <div class="content">
+      <byTable
+        :source="sourceList.data"
+        :pagination="sourceList.pagination"
+        :config="config"
+        :loading="loading"
+        highlight-current-row
+        :selectConfig="selectConfig"
+        :action-list="[
+          {
+            text: '添加签名',
+            action: () => openModal(),
+          },
+        ]"
+        @moreSearch="moreSearch"
+        @get-list="getList"
+      >
+        <template #content="{ item }">
+          <div v-if="item.content">
+            <div v-html="getHtml(item.content)"></div>
+          </div>
+        </template>
+      </byTable>
+    </div>
+
+    <el-dialog
+      :title="submitType == 'add' ? '添加模板' : '编辑模板'"
+      v-if="addDialog"
+      v-model="addDialog"
+      width="60%"
+    >
+      <byForm
+        :formConfig="formConfig"
+        :formOption="formOption"
+        v-model="formData.data"
+        :rules="rules"
+        ref="byform"
+      >
+        <template #content>
+          <div style="width: 100%">
+            <Editor
+              :value="formData.data.content"
+              @updateValue="updateHandover"
+            />
+          </div>
+        </template>
+      </byForm>
+      <template #footer>
+        <el-button @click="addDialog = false" size="large">取 消</el-button>
+        <el-button
+          type="primary"
+          @click="submitForm()"
+          size="large"
+          :loading="submitLoading"
+          >确 定</el-button
+        >
+      </template>
+    </el-dialog>
+
+    <el-dialog
+      title="预览"
+      v-if="previewDialog"
+      v-model="previewDialog"
+      width="60%"
+    >
+      <div style="width: 100%" class="main">
+        <img src="@/assets/images/mail-preview.png" alt="" class="img" />
+        <div class="body">
+          <div v-html="getHtml(selectRowData.content)"></div>
+        </div>
+      </div>
+      <div style="display: flex; align-items: center; margin-top: 20px">
+        <div style="margin-right: 5px">选择签名</div>
+        <el-select disabled v-model="selectRowData.templateName"> </el-select>
+      </div>
+      <template #footer>
+        <el-button @click="previewDialog = false" size="large">取 消</el-button>
+      </template>
+    </el-dialog>
+  </div>
+</template>
+
+<script setup>
+import { ElMessage, ElMessageBox } from "element-plus";
+import byTable from "@/components/byTable/index";
+import byForm from "@/components/byForm/index";
+import Editor from "@/components/Editor/index.vue";
+
+const loading = ref(false);
+const sourceList = ref({
+  data: [],
+  pagination: {
+    total: 0,
+    pageNum: 1,
+    pageSize: 10,
+    type: "",
+    keyword: "",
+  },
+});
+const { proxy } = getCurrentInstance();
+const selectConfig = computed(() => {
+  return [];
+});
+const config = computed(() => {
+  return [
+    {
+      attrs: {
+        label: "模板名称",
+        prop: "templateName",
+        width: 180,
+      },
+    },
+    {
+      attrs: {
+        label: "签名内容",
+        prop: "content",
+        slot: "content",
+      },
+    },
+    {
+      attrs: {
+        label: "创建时间",
+        prop: "createTime",
+        width: 155,
+      },
+    },
+    {
+      attrs: {
+        label: "操作",
+        width: "160",
+        align: "center",
+        fixed: "right",
+      },
+      renderHTML(row) {
+        return [
+          {
+            attrs: {
+              label: "预览",
+              type: "primary",
+              text: true,
+            },
+            el: "button",
+            click() {
+              openModalOne(row);
+            },
+          },
+          {
+            attrs: {
+              label: "修改",
+              type: "primary",
+              text: true,
+            },
+            el: "button",
+            click() {
+              getDtl(row);
+            },
+          },
+          {
+            attrs: {
+              label: "删除",
+              type: "primary",
+              text: true,
+            },
+            el: "button",
+            click() {
+              // 弹窗提示是否删除
+              ElMessageBox.confirm(
+                "此操作将永久删除该数据, 是否继续?",
+                "提示",
+                {
+                  confirmButtonText: "确定",
+                  cancelButtonText: "取消",
+                  type: "warning",
+                }
+              ).then(() => {
+                // 删除
+                proxy
+                  .post("/mailSignature/delete", {
+                    id: row.id,
+                  })
+                  .then((res) => {
+                    ElMessage({
+                      message: "删除成功",
+                      type: "success",
+                    });
+                    getList();
+                  });
+              });
+            },
+          },
+        ];
+      },
+    },
+  ];
+});
+const getList = async (req) => {
+  sourceList.value.pagination = { ...sourceList.value.pagination, ...req };
+  loading.value = true;
+  proxy
+    .post("/mailSignature/page", sourceList.value.pagination)
+    .then((message) => {
+      sourceList.value.data = message.rows;
+      sourceList.value.pagination.total = message.total;
+      setTimeout(() => {
+        loading.value = false;
+      }, 200);
+    });
+};
+getList();
+const formData = reactive({
+  data: {},
+});
+const formOption = reactive({
+  inline: true,
+  labelWidth: 100,
+  itemWidth: 100,
+  rules: [],
+});
+const formConfig = computed(() => {
+  return [
+    {
+      type: "input",
+      prop: "templateName",
+      label: "模板名称",
+    },
+    {
+      type: "slot",
+      prop: "content",
+      label: "签名内容",
+      slotName: "content",
+    },
+  ];
+});
+const rules = ref({
+  templateName: [
+    { required: true, message: "请输入模板名称", trigger: "blur" },
+  ],
+  content: [{ required: true, message: "请输入签名内容", trigger: "blur" }],
+});
+const submitType = ref("add");
+const addDialog = ref(false);
+const submitLoading = ref(false);
+const byform = ref(null);
+const openModal = () => {
+  submitType.value = "add";
+  formData.data = {
+    content: "",
+  };
+  addDialog.value = true;
+};
+const updateHandover = (val) => {
+  formData.data.content = val;
+};
+const submitForm = () => {
+  byform.value.handleSubmit(() => {
+    submitLoading.value = true;
+    proxy.post("/mailSignature/" + submitType.value, formData.data).then(
+      () => {
+        ElMessage({
+          message: "操作成功",
+          type: "success",
+        });
+        addDialog.value = false;
+        submitLoading.value = false;
+        getList();
+      },
+      () => {
+        submitLoading.value = false;
+      }
+    );
+  });
+};
+const getDtl = (row) => {
+  submitType.value = "edit";
+  proxy.post("/mailSignature/detail", { id: row.id }).then((res) => {
+    addDialog.value = true;
+    formData.data = res;
+  });
+};
+
+const getHtml = (str) => {
+  if (str) {
+    let newStr = str.replace(/<p\b/gi, "<div"); // 使用正则表达式替换<p>为<div
+    return newStr.replace(/<\/p>/gi, "</div>"); // 使用正则表达式替换</p>为</div>
+  }
+};
+
+const selectRowData = ref({});
+const previewDialog = ref(false);
+const openModalOne = (row) => {
+  selectRowData.value = row;
+  previewDialog.value = true;
+};
+</script>
+
+<style lang="scss" scoped>
+.tenant {
+  padding: 20px;
+}
+.ql-editor {
+  padding: 0px;
+}
+.main {
+  position: relative;
+  .img {
+    width: 100%;
+    // height: 500px;
+    object-fit: contain;
+    vertical-align: middle;
+  }
+  .body {
+    padding: 10px;
+    position: absolute;
+    background: #fff;
+    min-height: 20%;
+    left: 6%;
+    bottom: 16px;
+    min-width: 50%;
+    overflow: auto;
+  }
+}
+</style>

+ 776 - 0
src/views/purchaseManage/purchaseManage/handoverSlipNew/index.vue

@@ -0,0 +1,776 @@
+<template>
+  <div class="tenant">
+    <byTable
+      :source="sourceList.data"
+      :pagination="sourceList.pagination"
+      :config="config"
+      :loading="loading"
+      highlight-current-row
+      :selectConfig="selectConfig"
+      :row-class-name="getRowClass"
+      :table-events="{
+        select: selectRow,
+      }"
+      :action-list="[
+        {
+          text: '转生产',
+          disabled: selectData.length === 0,
+          action: () => transferToProduction(),
+        },
+        {
+          text: '采购',
+          disabled: selectData.length === 0,
+          action: () => start(),
+        },
+      ]"
+      @get-list="getList"
+    >
+      <template #claimTime="{ item }">
+        <div>
+          <span v-if="item.claimTime">{{ item.claimTime }}</span>
+          <span v-else>未到账</span>
+        </div>
+      </template>
+      <template #details="{ item }">
+        <div>
+          <el-button
+            type="primary"
+            link
+            v-if="item.expendQuantity >= 0"
+            @click="handleClickDetails(item)"
+            >查看</el-button
+          >
+          <el-button
+            type="primary"
+            link
+            style="color: #f54a45"
+            v-else
+            @click="handleClickDetails(item)"
+            >查看</el-button
+          >
+        </div>
+      </template>
+      <template #btn="{ item }">
+        <div v-if="item.expendQuantity > 0">
+          <el-button type="primary" link @click="start(10, item)"
+            >采购</el-button
+          >
+          <el-button type="primary" link @click="transferToProduction(item)"
+            >转生产</el-button
+          >
+        </div>
+        <div v-else-if="item.expendQuantity == 0">
+          <el-button type="primary" link @click="handleFollow(item)"
+            >跟进</el-button
+          >
+          <el-button type="primary" link @click="lookRecords(item)"
+            >跟进记录</el-button
+          >
+        </div>
+        <div v-else>
+          <el-button
+            type="primary"
+            link
+            style="color: #f54a45"
+            @click="handleFollow(item)"
+            >跟进</el-button
+          >
+          <el-button
+            type="primary"
+            link
+            style="color: #f54a45"
+            @click="lookRecords(item)"
+            >跟进记录</el-button
+          >
+        </div>
+      </template>
+    </byTable>
+
+    <el-dialog
+      title="转生产"
+      v-if="dialogVisible"
+      v-model="dialogVisible"
+      width="1200"
+      v-loading="loadingDialog"
+    >
+      <byForm
+        :formConfig="formConfig"
+        :formOption="formOption"
+        v-model="formData.data"
+        :rules="rules"
+        ref="submit"
+      >
+        <template #details>
+          <div style="width: 100%">
+            <el-table
+              :data="formData.data.list"
+              style="width: 100%; margin-top: 16px"
+            >
+              <el-table-column
+                prop="productCode"
+                label="物品编码"
+                width="140"
+              />
+              <el-table-column
+                prop="productName"
+                label="物品名称"
+                min-width="220"
+              />
+              <el-table-column
+                prop="productUnit"
+                label="单位"
+                width="100"
+                :formatter="
+                  (row) => dictValueLabel(row.productUnit, productUnit)
+                "
+              />
+              <el-table-column
+                prop="expendQuantity"
+                label="待处理数量"
+                width="120"
+              />
+              <el-table-column label="转生产数量" width="160">
+                <template #default="{ row, $index }">
+                  <div style="width: 100%">
+                    <el-form-item
+                      :prop="'list.' + $index + '.quantity'"
+                      :rules="rules.quantity"
+                      :inline-message="true"
+                    >
+                      <el-input-number
+                        v-model="row.quantity"
+                        placeholder="请输入数量"
+                        style="width: 100%"
+                        :precision="0"
+                        :controls="false"
+                        :min="0"
+                      />
+                    </el-form-item>
+                  </div>
+                </template>
+              </el-table-column>
+              <el-table-column label="完工期限" width="180">
+                <template #default="{ row, $index }">
+                  <div style="width: 100%">
+                    <el-form-item
+                      :prop="'list.' + $index + '.time'"
+                      :rules="rules.time"
+                      :inline-message="true"
+                    >
+                      <el-date-picker
+                        v-model="row.time"
+                        type="date"
+                        placeholder="请选择"
+                        value-format="YYYY-MM-DD"
+                      />
+                    </el-form-item>
+                  </div>
+                </template>
+              </el-table-column>
+              <el-table-column
+                align="center"
+                label="操作"
+                width="80"
+                fixed="right"
+              >
+                <template #default="{ row, $index }">
+                  <el-button type="primary" link @click="handleDelete($index)"
+                    >删除</el-button
+                  >
+                </template>
+              </el-table-column>
+            </el-table>
+          </div>
+        </template>
+      </byForm>
+      <template #footer>
+        <el-button @click="dialogVisible = false" size="large">取 消</el-button>
+        <el-button type="primary" @click="submitForm()" size="large"
+          >确 定</el-button
+        >
+      </template>
+    </el-dialog>
+    <el-dialog
+      title="填写跟进"
+      v-if="dialogVisibleOne"
+      v-model="dialogVisibleOne"
+      width="500"
+      v-loading="loadingDialog"
+    >
+      <byForm
+        :formConfig="formConfigOne"
+        :formOption="formOption"
+        v-model="formData.dataOne"
+        :rules="rulesOne"
+        ref="submitOne"
+      >
+      </byForm>
+      <template #footer>
+        <el-button @click="dialogVisibleOne = false" size="large"
+          >取 消</el-button
+        >
+        <el-button type="primary" @click="submitFormOne()" size="large"
+          >确 定</el-button
+        >
+      </template>
+    </el-dialog>
+
+    <el-dialog title="跟进记录" v-model="dialogVisibleTwo" width="500">
+      <div style="width: 100%">
+        <el-timeline :reverse="false">
+          <el-timeline-item
+            placement="top"
+            v-for="(activity, index) in activities"
+            :key="index"
+            :timestamp="activity.followUpTime"
+          >
+            <div>
+              跟进结果:
+              <span>{{ activity.resultType ? "已处理" : "处理中" }}</span>
+            </div>
+            <div style="margin-top: 5px">跟进记录: {{ activity.remark }}</div>
+          </el-timeline-item>
+        </el-timeline>
+      </div>
+    </el-dialog>
+
+    <el-dialog
+      title="交接单"
+      v-if="openHandover"
+      v-model="openHandover"
+      width="800"
+    >
+      <byForm
+        :formConfig="formHandoverConfig"
+        :formOption="formOption"
+        v-model="productRow.data"
+      >
+        <template #remark>
+          <div style="width: 100%">
+            <Editor
+              ref="remarkEditor"
+              :readOnly="true"
+              :value="productRow.data.remark"
+            />
+          </div>
+        </template>
+        <template #file>
+          <div style="width: 100%">
+            <el-upload
+              v-model:fileList="productRow.data.fileList"
+              action="https://winfaster.obs.cn-south-1.myhuaweicloud.com"
+              multiple
+              :on-preview="onPreviewFile"
+            >
+            </el-upload>
+          </div>
+        </template>
+      </byForm>
+      <template #footer>
+        <el-button @click="openHandover = false" size="large">关 闭</el-button>
+      </template>
+    </el-dialog>
+  </div>
+</template>
+
+<script setup>
+import byTable from "@/components/byTable/index";
+import byForm from "@/components/byForm/index";
+import { computed, nextTick, ref } from "vue";
+import { ElMessage } from "element-plus";
+import Editor from "@/components/Editor/index.vue";
+
+const { proxy } = getCurrentInstance();
+const loading = ref(false);
+const sourceList = ref({
+  data: [],
+  pagination: {
+    total: 3,
+    pageNum: 1,
+    pageSize: 10,
+    status: "15",
+  },
+});
+const isReceivedArr = ref([
+  { label: "是", value: "1" },
+  { label: "否", value: "0" },
+]);
+const corporationArr = ref([]);
+const selectConfig = computed(() => [
+  {
+    label: "归属公司",
+    prop: "corporationId",
+    data: corporationArr.value,
+  },
+  {
+    label: "是否到账",
+    prop: "isReceived",
+    data: isReceivedArr.value,
+  },
+]);
+const config = computed(() => {
+  return [
+    {
+      type: "selection",
+      attrs: {
+        checkAtt: "isCheck",
+      },
+    },
+    {
+      attrs: {
+        label: "归属公司",
+        prop: "corporationName",
+      },
+    },
+    {
+      attrs: {
+        label: "外销合同编号",
+        prop: "contractCode",
+        width: "160",
+      },
+    },
+    {
+      attrs: {
+        label: "下单时间",
+        prop: "contractTime",
+        width: "155",
+      },
+    },
+    {
+      attrs: {
+        label: "合同到账时间",
+        slot: "claimTime",
+        width: "155",
+      },
+    },
+    {
+      attrs: {
+        label: "业务员",
+        prop: "userName",
+      },
+    },
+    {
+      attrs: {
+        label: "版本号",
+        prop: "contractVersion",
+      },
+      render(contractVersion) {
+        return "v" + contractVersion;
+      },
+    },
+    {
+      attrs: {
+        label: "产品编码",
+        prop: "productCode",
+      },
+    },
+    {
+      attrs: {
+        label: "产品名称",
+        prop: "productName",
+      },
+    },
+    {
+      attrs: {
+        label: "单位",
+        prop: "productUnit",
+        width: "80",
+      },
+      render(unit) {
+        return proxy.dictValueLabel(unit, productUnit.value);
+      },
+    },
+    {
+      attrs: {
+        label: "已发起数量",
+        prop: "startPurchaseCount",
+        width: "110",
+      },
+    },
+    {
+      attrs: {
+        label: "待处理数量",
+        prop: "expendQuantity",
+        width: "110",
+      },
+    },
+    {
+      attrs: {
+        label: "详情",
+        width: "100",
+        align: "center",
+        slot: "details",
+      },
+    },
+    {
+      attrs: {
+        label: "操作",
+        slot: "btn",
+        width: "140",
+        align: "center",
+        fixed: "right",
+      },
+    },
+  ];
+});
+
+const getList = async (req) => {
+  sourceList.value.pagination = { ...sourceList.value.pagination, ...req };
+  loading.value = true;
+  proxy
+    .post("/contractProduct/pageNew", sourceList.value.pagination)
+    .then((message) => {
+      sourceList.value.data = message.rows.map((x) => ({
+        ...x,
+        isCheck: true,
+      }));
+      sourceList.value.pagination.total = message.total;
+      setTimeout(() => {
+        loading.value = false;
+      }, 200);
+    });
+};
+getList();
+const productUnit = ref([]);
+const getDict = () => {
+  proxy
+    .post("/corporation/page", { pageNum: 1, pageSize: 9999 })
+    .then((res) => {
+      corporationArr.value = res.rows.map((x) => ({
+        ...x,
+        label: x.name,
+        value: x.id,
+      }));
+    });
+  proxy.getDictOne(["unit"]).then((res) => {
+    productUnit.value = res["unit"].map((x) => ({
+      label: x.dictValue,
+      value: x.dictKey,
+    }));
+  });
+};
+getDict();
+const selectData = ref([]);
+const selectRow = (data) => {
+  selectData.value = data;
+};
+const start = (type, row) => {
+  if (type === 10) {
+    selectData.value = [row];
+  }
+  if (selectData.value.length > 0) {
+    let ids = selectData.value.map((x) => x.id).join();
+    let arr = selectData.value.map((x) => ({
+      contractId: x.contractId,
+      contractCode: x.contractCode,
+      claimTime: x.contractTime,
+    }));
+    let newArr = [];
+    for (let i = 0; i < arr.length; i++) {
+      const e = arr[i];
+      let flag = newArr.some((x) => x.contractId === e.contractId);
+      if (!flag) {
+        newArr.push(e);
+      }
+    }
+    proxy.$router.replace({
+      path: "/platform_manage/process/processApproval",
+      query: {
+        flowKey: "purchase_flow",
+        type: "handoverSlip",
+        random: proxy.random(),
+        ids,
+        arr: JSON.stringify(newArr),
+      },
+    });
+  } else {
+    return ElMessage({
+      message: "请勾选数据!",
+      type: "info",
+    });
+  }
+};
+const dialogVisible = ref(false);
+const dialogVisibleOne = ref(false);
+const dialogVisibleTwo = ref(false);
+const loadingDialog = ref(false);
+const submit = ref(null);
+const submitOne = ref(null);
+const formOption = reactive({
+  inline: true,
+  labelWidth: 100,
+  itemWidth: 100,
+  rules: [],
+});
+const formData = reactive({
+  data: {
+    list: [],
+  },
+  dataOne: {},
+});
+const formConfig = computed(() => {
+  return [
+    {
+      type: "slot",
+      slotName: "details",
+      label: "产品明细",
+    },
+  ];
+});
+const rules = ref({
+  quantity: [{ required: true, message: "请输入数量", trigger: "blur" }],
+  time: [{ required: true, message: "请选择完工期限", trigger: "change" }],
+});
+
+const formConfigOne = computed(() => {
+  return [
+    {
+      type: "select",
+      prop: "resultType",
+      label: "跟进结果",
+      data: [
+        {
+          label: "处理中",
+          value: "0",
+        },
+        {
+          label: "已处理",
+          value: "1",
+        },
+      ],
+    },
+    {
+      type: "date",
+      itemType: "datetime",
+      prop: "followUpTime",
+      label: "跟进时间",
+      format: "YYYY-MM-DD HH:mm:ss",
+    },
+    {
+      type: "input",
+      prop: "remark",
+      label: "跟进记录",
+      itemType: "textarea",
+    },
+  ];
+});
+
+const rulesOne = ref({
+  resultType: [
+    { required: true, message: "请选择跟进结果", trigger: "change" },
+  ],
+  followUpTime: [
+    { required: true, message: "请选择跟进时间", trigger: "change" },
+  ],
+  remark: [{ required: true, message: "请输入跟进记录", trigger: "blur" }],
+});
+
+const activities = ref([]);
+const lookRecords = (row) => {
+  proxy
+    .post("/contractProductFollowUp/list", {
+      contractProductId: row.productId,
+    })
+    .then((res) => {
+      if (res && res.length > 0) {
+        activities.value = res;
+        dialogVisibleTwo.value = true;
+      } else {
+        return ElMessage({
+          message: "暂无跟进记录!",
+          type: "info",
+        });
+      }
+    });
+};
+const handleFollow = (row) => {
+  formData.dataOne = {
+    contractProductId: row.productId,
+  };
+  dialogVisibleOne.value = true;
+};
+
+const submitFormOne = () => {
+  submitOne.value.handleSubmit(() => {
+    loadingDialog.value = true;
+    proxy.post("/contractProductFollowUp/add", formData.dataOne).then(
+      () => {
+        ElMessage({
+          message: "提交成功",
+          type: "success",
+        });
+        dialogVisibleOne.value = false;
+        getList();
+      },
+      (err) => {
+        console.log(err);
+        loadingDialog.value = false;
+      }
+    );
+  });
+};
+
+const transferToProduction = (row) => {
+  if (row && row.id) {
+    formData.data = {
+      list: [
+        {
+          sourceId: row.id,
+          source: "1",
+          productId: row.productId,
+          productCode: row.productCode,
+          productName: row.productName,
+          productUnit: row.productUnit,
+          expendQuantity: row.expendQuantity,
+          quantity: undefined,
+        },
+      ],
+    };
+  } else {
+    formData.data = {
+      list: selectData.value.map((item) => {
+        return {
+          sourceId: item.id,
+          source: "1",
+          productId: item.productId,
+          productCode: item.productCode,
+          productName: item.productName,
+          productUnit: item.productUnit,
+          expendQuantity: item.expendQuantity,
+          quantity: undefined,
+        };
+      }),
+    };
+  }
+  dialogVisible.value = true;
+};
+watch(selectData, (newVal) => {
+  if (newVal.length == 0) {
+    sourceList.value.data.forEach((x) => {
+      x.isCheck = true;
+    });
+  } else if (newVal.length == 1) {
+    const current = newVal[0];
+    sourceList.value.data.forEach((x) => {
+      if (x.contractId !== current.contractId) {
+        x.isCheck = false;
+      }
+    });
+  }
+});
+const submitForm = () => {
+  submit.value.handleSubmit(() => {
+    if (!(formData.data.list && formData.data.list.length > 0)) {
+      return ElMessage("请至少添加一条产品明细");
+    }
+    loadingDialog.value = true;
+    proxy.post("/workOrder/addBatch", formData.data.list).then(
+      () => {
+        ElMessage({
+          message: "提交成功",
+          type: "success",
+        });
+        dialogVisible.value = false;
+        getList();
+      },
+      (err) => {
+        console.log(err);
+        loadingDialog.value = false;
+      }
+    );
+  });
+};
+const handleDelete = (index) => {
+  formData.data.list.splice(index, 1);
+};
+
+const getRowClass = ({ row }) => {
+  if (row.expendQuantity < 0) {
+    return "redClass";
+  }
+  return "";
+};
+const openHandover = ref(false);
+const productRow = reactive({
+  data: {
+    productName: "",
+    productModel: "",
+    remark: "",
+    fileList: [],
+  },
+});
+const formHandoverConfig = computed(() => {
+  return [
+    {
+      type: "title",
+      title: "产品信息",
+      label: "",
+    },
+    {
+      type: "input",
+      prop: "productName",
+      label: "产品名称",
+      itemType: "text",
+      disabled: true,
+    },
+    {
+      type: "input",
+      prop: "productModel",
+      label: "规格型号",
+      itemType: "text",
+      disabled: true,
+    },
+    {
+      type: "slot",
+      slotName: "remark",
+      label: "交接单",
+    },
+    {
+      type: "slot",
+      prop: "file",
+      slotName: "file",
+      label: "附件",
+    },
+  ];
+});
+const remarkEditor = ref(null);
+const handleClickDetails = (row) => {
+  proxy
+    .post("/flowProcess/getStartData", { flowId: row.flowId })
+    .then(async (res) => {
+      const current = res.contractProductList.find(
+        (x) => x.productId === row.productId
+      );
+      productRow.data = current || {};
+      productRow.data.fileList =
+        current.fileList.map((x) => ({
+          raw: x,
+          name: x.fileName,
+          url: x.fileUrl,
+        })) || [];
+      openHandover.value = true;
+      await nextTick();
+      remarkEditor.value.changeHtml(productRow.data.remark);
+    });
+};
+const onPreviewFile = (file) => {
+  window.open(file.raw.fileUrl, "_blank");
+};
+</script>
+
+<style lang="scss" scoped>
+.tenant {
+  margin: 20px;
+}
+::v-deep(.el-input-number .el-input__inner) {
+  text-align: left;
+}
+:deep(.el-table__header-wrapper .el-checkbox) {
+  display: none;
+}
+</style>
+<style>
+.redClass {
+  color: #f54a45 !important;
+}
+</style>