Browse Source

销售合同模板

lxf 2 năm trước cách đây
mục cha
commit
73e33a58dc

+ 1 - 0
package.json

@@ -26,6 +26,7 @@
     "@antv/x6-plugin-transform": "^2.1.6",
     "@vue-flow/additional-components": "^1.3.3",
     "@vue-flow/core": "^1.18.2",
+    "@vueup/vue-quill": "^1.0.0-alpha.40",
     "@vueuse/core": "9.5.0",
     "axios": "0.27.2",
     "echarts": "5.4.0",

+ 89 - 0
src/components/Editor/index.vue

@@ -0,0 +1,89 @@
+<template>
+  <div>
+    <QuillEditor ref="myQuillEditor" theme="snow" v-model:content="content" :options="data.editorOption" contentType="html" @update:content="setValue()" />
+    <!-- 使用自定义图片上传 -->
+    <input type="file" hidden accept=".jpg,.png" ref="fileBtn" @change="handleUpload" />
+  </div>
+</template>
+
+<script setup>
+import { QuillEditor } from "@vueup/vue-quill";
+import "@vueup/vue-quill/dist/vue-quill.snow.css";
+import { reactive, onMounted, ref, toRaw, watch } from "vue";
+// import { backsite } from '@/api'
+
+const props = defineProps(["value"]);
+const emit = defineEmits(["updateValue"]);
+const content = ref("");
+const myQuillEditor = ref();
+// watch(() => props.value, (val) => {
+//   console.log(toRaw(myQuillEditor.value))
+//   toRaw(myQuillEditor.value).setHTML(val)
+// }, { deep: true })
+const fileBtn = ref();
+const data = reactive({
+  content: "",
+  editorOption: {
+    modules: {
+      toolbar: [
+        ["bold", "italic", "underline", "strike"],
+        [{ size: ["small", false, "large", "huge"] }],
+        [{ font: [] }],
+        [{ align: [] }],
+        [{ list: "ordered" }, { list: "bullet" }],
+        [{ indent: "-1" }, { indent: "+1" }],
+        [{ header: 1 }, { header: 2 }],
+        ["image"],
+        [{ direction: "rtl" }],
+        [{ color: [] }, { background: [] }],
+      ],
+    },
+    placeholder: "请输入内容...",
+  },
+});
+const imgHandler = (state) => {
+  if (state) {
+    fileBtn.value.click();
+  }
+};
+const setValue = () => {
+  const text = toRaw(myQuillEditor.value).getHTML();
+  emit("updateValue", text);
+};
+const handleUpload = (e) => {
+  const files = Array.prototype.slice.call(e.target.files);
+  // console.log(files, "files")
+  if (!files) {
+    return;
+  }
+  const formdata = new FormData();
+  formdata.append("file", files[0]);
+  backsite.uploadFile(formdata)
+    .then(res => {
+      if (res.data.url) {
+        const quill = toRaw(myQuillEditor.value).getQuill()
+        const length = quill.getSelection().index
+        // 插入图片,res为服务器返回的图片链接地址
+        quill.insertEmbed(length, 'image', res.data.url)
+        // 调整光标到最后
+        quill.setSelection(length + 1)
+      }
+    })
+};
+onMounted(() => {
+  const quill = toRaw(myQuillEditor.value).getQuill();
+  if (myQuillEditor.value) {
+    quill.getModule("toolbar").addHandler("image", imgHandler);
+  }
+  toRaw(myQuillEditor.value).setHTML(props.value);
+});
+</script>
+<style scoped lang="scss">
+:deep(.ql-editor) {
+  min-height: 180px;
+}
+:deep(.ql-formats) {
+  height: 21px;
+  line-height: 21px;
+}
+</style>

+ 1 - 3
src/views/customer/file/index.vue

@@ -26,7 +26,7 @@
     <el-dialog :title="modalType == 'add' ? '新增' : '编辑'" v-model="dialogVisible" width="800" v-loading="loadingOperation">
       <byForm :formConfig="formConfig" :formOption="formOption" v-model="formData.data" :rules="rules" ref="submit">
         <template #address>
-          <el-row :gutter="10" style="width: 100%; margin-left: -15px">
+          <el-row :gutter="10" style="width: 100%">
             <el-col :span="8">
               <el-form-item prop="countryId">
                 <el-select v-model="formData.data.countryId" placeholder="国家" @change="(val) => getCityData(val, '20', true)">
@@ -57,7 +57,6 @@
             </el-col>
           </el-row>
         </template>
-
         <template #person>
           <div>
             <el-button type="primary" @click="clickAddPerson"> 添加 </el-button>
@@ -152,7 +151,6 @@ const config = computed(() => {
         prop: "name",
       },
     },
-
     {
       attrs: {
         label: "所在城市",

+ 380 - 0
src/views/publicModule/contractTemplate/index.vue

@@ -0,0 +1,380 @@
+<template>
+  <div class="tenant">
+    <div class="content">
+      <byTable
+        :source="sourceList.data"
+        :pagination="sourceList.pagination"
+        :config="config"
+        :loading="loading"
+        :selectConfig="selectConfig"
+        highlight-current-row
+        :action-list="[
+          {
+            text: '添加模板',
+            action: () => openModal(),
+          },
+        ]"
+        @get-list="getList">
+      </byTable>
+    </div>
+
+    <el-dialog :title="modalType == 'add' ? '新增' : '编辑'" v-if="dialogVisible" v-model="dialogVisible" width="800" v-loading="loadingOperation">
+      <byForm :formConfig="formConfig" :formOption="formOption" v-model="formData.data" :rules="rules" ref="submit">
+        <template #allAddress>
+          <el-row :gutter="10" style="width: 100%">
+            <el-col :span="8">
+              <el-form-item prop="countryId">
+                <el-select v-model="formData.data.countryId" placeholder="国家" @change="(val) => getCityData(val, '20', true)">
+                  <el-option v-for="item in countryData" :label="item.chineseName" :value="item.id"> </el-option>
+                </el-select>
+              </el-form-item>
+            </el-col>
+            <el-col :span="8">
+              <el-form-item prop="provinceId">
+                <el-select v-model="formData.data.provinceId" placeholder="省/洲" @change="(val) => getCityData(val, '30', true)">
+                  <el-option v-for="item in provinceData" :label="item.name" :value="item.id"> </el-option>
+                </el-select>
+              </el-form-item>
+            </el-col>
+            <el-col :span="8">
+              <el-form-item prop="cityId">
+                <el-select v-model="formData.data.cityId" placeholder="城市">
+                  <el-option v-for="item in cityData" :label="item.name" :value="item.id"> </el-option>
+                </el-select>
+              </el-form-item>
+            </el-col>
+          </el-row>
+          <el-row style="margin-top: 20px; width: 100%">
+            <el-col :span="24">
+              <el-form-item prop="address">
+                <el-input v-model="formData.data.address" type="textarea"> </el-input>
+              </el-form-item>
+            </el-col>
+          </el-row>
+        </template>
+        <template #allAddressEnglish>
+          <el-row :gutter="10" style="width: 100%">
+            <el-col :span="8">
+              <el-form-item prop="countryEnStr">
+                <el-input v-model="formData.data.countryEnStr" placeholder="请输入国家 (英文)" />
+              </el-form-item>
+            </el-col>
+            <el-col :span="8">
+              <el-form-item prop="provinceEnStr">
+                <el-input v-model="formData.data.provinceEnStr" placeholder="请输入省/洲 (英文)" />
+              </el-form-item>
+            </el-col>
+            <el-col :span="8">
+              <el-form-item prop="cityEnStr">
+                <el-input v-model="formData.data.cityEnStr" placeholder="请输入城市 (英文)" />
+              </el-form-item>
+            </el-col>
+          </el-row>
+          <el-row style="margin-top: 20px; width: 100%">
+            <el-col :span="24">
+              <el-form-item prop="addressEn">
+                <el-input v-model="formData.data.addressEn" type="textarea"> </el-input>
+              </el-form-item>
+            </el-col>
+          </el-row>
+        </template>
+        <template #templateContent>
+          <div style="width: 100%">
+            <Editor :value="formData.data.templateContent" @updateValue="updateContent"/>
+          </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>
+  </div>
+</template>
+
+<script setup>
+import { ElMessage, ElMessageBox } from "element-plus";
+import byTable from "@/components/byTable/index";
+import byForm from "@/components/byForm/index";
+import { computed, ref } from "vue";
+import Editor from "@/components/Editor/index.vue";
+
+const { proxy } = getCurrentInstance();
+const loading = ref(false);
+const companyList = ref({});
+const sourceList = ref({
+  data: [],
+  pagination: {
+    total: 0,
+    pageNum: 1,
+    pageSize: 10,
+    corporationId: "",
+    keyword: "",
+  },
+});
+const selectConfig = computed(() => {
+  return [
+    {
+      label: "公司名称",
+      prop: "corporationId",
+      data: companyList.value,
+    },
+  ];
+});
+const config = computed(() => {
+  return [
+    {
+      attrs: {
+        label: "公司名称",
+        prop: "corporationName",
+      },
+    },
+    {
+      attrs: {
+        label: "模板名称",
+        prop: "templateName",
+      },
+    },
+    {
+      attrs: {
+        label: "联系人",
+        prop: "contactName",
+      },
+    },
+    {
+      attrs: {
+        label: "联系电话",
+        prop: "contactNumber",
+      },
+    },
+    {
+      attrs: {
+        label: "操作",
+        width: "120",
+        align: "center",
+      },
+      renderHTML(row) {
+        return [
+          {
+            attrs: {
+              label: "修改",
+              type: "primary",
+              text: true,
+            },
+            el: "button",
+            click() {
+              update(row);
+            },
+          },
+          {
+            attrs: {
+              label: "删除",
+              type: "primary",
+              text: true,
+            },
+            el: "button",
+            click() {
+              ElMessageBox.confirm("此操作将永久删除该数据, 是否继续?", "提示", {
+                confirmButtonText: "确定",
+                cancelButtonText: "取消",
+                type: "warning",
+              }).then(() => {
+                proxy
+                  .post("/contractTemplate/delete", {
+                    id: row.id,
+                  })
+                  .then(() => {
+                    ElMessage({
+                      message: "删除成功",
+                      type: "success",
+                    });
+                    getList();
+                  });
+              });
+            },
+          },
+        ];
+      },
+    },
+  ];
+});
+const getDict = () => {
+  proxy.post("/corporation/page", { pageNum: 1, pageSize: 999 }).then((res) => {
+    companyList.value = res.rows.map((item) => {
+      return {
+        label: item.name,
+        value: item.id,
+      };
+    });
+  });
+};
+const getList = async (req) => {
+  sourceList.value.pagination = { ...sourceList.value.pagination, ...req };
+  loading.value = true;
+  proxy.post("/contractTemplate/page", sourceList.value.pagination).then((res) => {
+    sourceList.value.data = res.rows;
+    sourceList.value.pagination.total = res.total;
+    setTimeout(() => {
+      loading.value = false;
+    }, 200);
+  });
+};
+getDict();
+getList();
+const modalType = ref("add");
+const dialogVisible = ref(false);
+const loadingOperation = ref(false);
+const submit = ref(null);
+const formData = reactive({
+  data: {
+    countryId: "China",
+  },
+});
+const formOption = reactive({
+  inline: true,
+  labelWidth: 100,
+  itemWidth: 100,
+  rules: [],
+});
+const formConfig = computed(() => {
+  return [
+    {
+      label: "基础信息",
+    },
+    {
+      type: "input",
+      prop: "templateName",
+      label: "模板名称",
+      itemType: "text",
+      placeholder: "请输入模板名称",
+    },
+    {
+      type: "select",
+      label: "公司名称",
+      prop: "corporationId",
+      data: companyList.value,
+    },
+    {
+      label: "联系信息",
+    },
+    {
+      type: "input",
+      prop: "contactName",
+      label: "业务联系人",
+      itemType: "text",
+      placeholder: "请输入联系人",
+      itemWidth: 30,
+    },
+    {
+      type: "input",
+      prop: "contactNumber",
+      label: "  ",
+      itemType: "text",
+      placeholder: "请输入联系电话",
+      itemWidth: 70,
+    },
+    {
+      type: "input",
+      prop: "corporationNumber",
+      label: "公司电话",
+      itemType: "text",
+      placeholder: "请输入公司电话",
+    },
+    {
+      type: "slot",
+      slotName: "allAddress",
+      label: "公司地址",
+    },
+    {
+      type: "slot",
+      slotName: "allAddressEnglish",
+      label: "公司地址 (英文)",
+    },
+    {
+      type: "slot",
+      slotName: "templateContent",
+      label: "合同模板",
+    },
+  ];
+});
+let rules = ref({
+  templateName: [{ required: true, message: "请输入模板名称", trigger: "blur" }],
+  corporationId: [{ required: true, message: "请选择公司", trigger: "change" }],
+  countryId: [{ required: true, message: "请选择国家", trigger: "change" }],
+  provinceId: [{ required: true, message: "请选择省/州", trigger: "change" }],
+  countryEnStr: [{ required: true, message: "请输入国家 (英文)", trigger: "blur" }],
+  provinceEnStr: [{ required: true, message: "请输入省/洲 (英文)", trigger: "blur" }],
+  //   cityId: [{ required: true, message: "请选择城市", trigger: "change" }],
+});
+const countryData = ref([]);
+const provinceData = ref([]);
+const cityData = ref([]);
+const getCityData = (id, type, isChange) => {
+  proxy.post("/areaInfo/list", { parentId: id }).then((res) => {
+    if (type === "20") {
+      provinceData.value = res;
+      if (isChange) {
+        formData.data.provinceId = "";
+        formData.data.cityId = "";
+      }
+    } else if (type === "30") {
+      cityData.value = res;
+      if (isChange) {
+        formData.data.cityId = "";
+      }
+    } else {
+      countryData.value = res;
+    }
+  });
+};
+getCityData("0");
+const openModal = () => {
+  modalType.value = "add";
+  formData.data = {
+    templateContent: "",
+    countryId: "China",
+  };
+  getCityData(formData.data.countryId, "20");
+  loadingOperation.value = false;
+  dialogVisible.value = true;
+};
+const submitForm = () => {
+  submit.value.handleSubmit(() => {
+    loadingOperation.value = true;
+    proxy.post("/contractTemplate/" + modalType.value, formData.data).then(
+      () => {
+        ElMessage({
+          message: modalType.value == "add" ? "添加成功" : "编辑成功",
+          type: "success",
+        });
+        dialogVisible.value = false;
+        getList();
+      },
+      (err) => {
+        console.log(err);
+        loadingOperation.value = false;
+      }
+    );
+  });
+};
+const update = (row) => {
+  modalType.value = "edit";
+  loadingOperation.value = true;
+  proxy.post("/contractTemplate/detail", { id: row.id }).then((res) => {
+    formData.data = res;
+    getCityData(formData.data.countryId, "20");
+    getCityData(formData.data.provinceId, "30");
+    loadingOperation.value = false;
+    dialogVisible.value = true;
+  });
+};
+const updateContent = (val) => {
+  formData.data.templateContent = val
+}
+</script>
+
+<style lang="scss" scoped>
+.tenant {
+  padding: 20px;
+}
+</style>