Просмотр исходного кода

Merge branch 'purchaseDev' of http://172.16.100.139/new-business/drp-web into purchaseDev

黄梓星 2 лет назад
Родитель
Сommit
d1dd2c6915

+ 9 - 2
src/api/business/purchase/purchase-contract.js

@@ -1,10 +1,17 @@
 import request from "@/utils/request";
 
-// 查询任务列表
-export function taskList(params) {
+export function list(params) {
   return request({
     url: "/pu/contract/list",
     method: "get",
     params: params,
   });
 }
+
+export function add(data) {
+  return request({
+    url: "/pu/contract/add",
+    method: "post",
+    data: data,
+  });
+}

+ 9 - 0
src/views/common-dialog/api/index.js

@@ -0,0 +1,9 @@
+import request from "@/utils/request";
+
+export function list(url, params) {
+  return request({
+    url: `/pu/contract/${url}/list`,
+    method: "get",
+    params: params,
+  });
+}

+ 214 - 0
src/views/common-dialog/currency.vue

@@ -0,0 +1,214 @@
+<script>
+import { initParams } from "./utils/init-something";
+import { list } from "./api/index";
+
+export default {
+  name: "CurrencyInputDialog",
+  props: ["title", "value"],
+  components: {},
+  data() {
+    const columns = [
+      {
+        key: "name",
+        title: "币种",
+        type: "Input",
+        search: true,
+      },
+      {
+        key: "code",
+        title: "币种简称",
+        type: "Input",
+        search: true,
+      },
+      {
+        key: "",
+        title: "单价精度",
+      },
+      {
+        key: "",
+        title: "单价舍入规则",
+      },
+      {
+        key: "",
+        title: "金额精度",
+      },
+      {
+        key: "",
+        title: "金额舍入规则",
+      },
+    ];
+    const initTableColumns = () => columns.filter((column) => column.key);
+    const initSearchColumns = () => columns.filter((column) => column.search);
+    return {
+      // global
+      size: "mini",
+      width: "50%",
+      page: { pageNum: 1, pageSize: 25, total: 0 },
+      pageSizes: [25, 50],
+      layout: "prev, pager, next, jumper",
+      api: "puCurrType",
+      showKey: "name",
+      // dialog
+      visible: false,
+      loading: false,
+      // search
+      searchColumns: initSearchColumns(),
+      params: initParams(initSearchColumns()),
+      // table
+      tableColumns: initTableColumns(),
+      data: [],
+      currentData: null,
+    };
+  },
+  computed: {},
+  watch: {},
+  methods: {
+    // set dialog visible
+    setVisible(prop) {
+      this.visible = prop;
+    },
+    // do something before dialog open
+    beforeOpen() {
+      const { value } = this.$props;
+      this.params[this.showKey] = value;
+      this.fetchList(this.params, this.page);
+    },
+    // fetch table data
+    async fetchList(prop, page) {
+      try {
+        this.loading = true;
+        const { pageNum, pageSize } = page;
+        const { code, msg, rows, total } = await list(this.api, {
+          ...prop,
+          pageNum,
+          pageSize,
+        });
+        if (code === 200) {
+          this.data = rows;
+          this.page.total = total;
+          this.$notify.success({ title: msg });
+        } else {
+          this.$notify.warning({ title: msg });
+        }
+      } catch (err) {
+        this.$notify.error({ title: "error", message: err });
+      } finally {
+        this.loading = false;
+        this.setCurrentData(
+          this.data.find(
+            (column) => column[this.showKey] === this.currentData[this.showKey]
+          )
+        );
+      }
+    },
+    // setting up to fetch table data
+    queryList() {
+      this.fetchList(this.params, this.page);
+    },
+    // reset to fetch table data
+    resetList() {
+      this.page.pageNum = 1;
+      this.params = initParams(this.searchColumns);
+      this.fetchList(this.params, this.page);
+    },
+    // size change to fetch table data
+    pageSizeChange(prop) {
+      this.page.pageSize = prop;
+      this.fetchList(this.params, this.page);
+    },
+    // number change to fetch table data
+    pageNumberChange(prop) {
+      this.page.pageNum = prop;
+      this.fetchList(this.params, this.page);
+    },
+    // select row data
+    selectCurrentData(row) {
+      this.currentData = row;
+    },
+    // set row data highlight
+    setCurrentData(row) {
+      this.$refs.singleTable.setCurrentRow(row);
+    },
+    //
+    confirm() {
+      if (this.currentData) {
+        this.$emit("confirm", this.currentData);
+      }
+      this.setVisible(false);
+    },
+  },
+  created() {},
+  mounted() {},
+  destroyed() {},
+};
+</script>
+<template>
+  <el-dialog
+    :title="title"
+    :visible.sync="visible"
+    :width="width"
+    append-to-body
+    @open="beforeOpen"
+  >
+    <el-form :size="size" :inline="true" :model="params">
+      <el-form-item
+        v-for="(column, index) in searchColumns"
+        :key="index"
+        :label="column.title"
+      >
+        <el-input v-model="params[column.key]" @change="queryList"> </el-input>
+      </el-form-item>
+      <el-form-item>
+        <el-button icon="el-icon-refresh" @click="resetList"></el-button>
+      </el-form-item>
+    </el-form>
+    <el-table
+      v-loading="loading"
+      :data="data"
+      :size="size"
+      ref="singleTable"
+      height="45vh"
+      highlight-current-row
+      style="width: 100%; margin-bottom: 20px"
+      @row-click="selectCurrentData"
+    >
+      <el-table-column
+        v-for="(column, index) in tableColumns"
+        :key="index"
+        :prop="column.key"
+        :label="column.title"
+        :width="column.width"
+        show-overflow-tooltip
+      >
+      </el-table-column>
+    </el-table>
+    <div
+      style="display: flex; justify-content: space-between; align-items: center"
+    >
+      <p>
+        <span style="font-size: 12px">已选择 :</span>
+        <el-tag v-if="currentData" :size="size">{{
+          currentData[showKey]
+        }}</el-tag>
+        <span v-else>无</span>
+      </p>
+      <el-pagination
+        :layout="layout"
+        :total="page.total"
+        :page-sizes="pageSizes"
+        :page-size="page.pageSize"
+        :current-page="page.pageNum"
+        :small="size === 'mini'"
+        background
+        @size-change="pageSizeChange"
+        @current-change="pageNumberChange"
+      >
+      </el-pagination>
+    </div>
+    <div style="margin-top: 20px; text-align: right">
+      <el-button :size="size" @click="visible = false">取 消</el-button>
+      <el-button :size="size" type="primary" @click="confirm">确 定</el-button>
+    </div>
+  </el-dialog>
+</template>
+<style scoped></style>

+ 198 - 0
src/views/common-dialog/department.vue

@@ -0,0 +1,198 @@
+<script>
+import { initParams } from "./utils/init-something";
+import { list } from "./api/index";
+
+export default {
+  name: "DepartmentInputDialog",
+  props: ["title", "value"],
+  components: {},
+  data() {
+    const columns = [
+      {
+        key: "deptId",
+        title: "组织编码",
+        type: "Input",
+        search: true,
+      },
+      {
+        key: "deptName",
+        title: "组织名称",
+        type: "Input",
+        search: true,
+      },
+    ];
+    const initTableColumns = () => columns.filter((column) => column.key);
+    const initSearchColumns = () => columns.filter((column) => column.search);
+    return {
+      // global
+      size: "mini",
+      width: "50%",
+      page: { pageNum: 1, pageSize: 25, total: 0 },
+      pageSizes: [25, 50],
+      layout: "prev, pager, next, jumper",
+      api: "puDept",
+      showKey: "deptName",
+      // dialog
+      visible: false,
+      loading: false,
+      // search
+      searchColumns: initSearchColumns(),
+      params: initParams(initSearchColumns()),
+      // table
+      tableColumns: initTableColumns(),
+      data: [],
+      currentData: null,
+    };
+  },
+  computed: {},
+  watch: {},
+  methods: {
+    // set dialog visible
+    setVisible(prop) {
+      this.visible = prop;
+    },
+    // do something before dialog open
+    beforeOpen() {
+      const { value } = this.$props;
+      this.params[this.showKey] = value;
+      this.fetchList(this.params, this.page);
+    },
+    // fetch table data
+    async fetchList(prop, page) {
+      try {
+        this.loading = true;
+        const { pageNum, pageSize } = page;
+        const { code, msg, rows, total } = await list(this.api, {
+          ...prop,
+          pageNum,
+          pageSize,
+        });
+        if (code === 200) {
+          this.data = rows;
+          this.page.total = total;
+          this.$notify.success({ title: msg });
+        } else {
+          this.$notify.warning({ title: msg });
+        }
+      } catch (err) {
+        this.$notify.error({ title: "error", message: err });
+      } finally {
+        this.loading = false;
+        this.setCurrentData(
+          this.data.find(
+            (column) => column[this.showKey] === this.currentData[this.showKey]
+          )
+        );
+      }
+    },
+    // setting up to fetch table data
+    queryList() {
+      this.fetchList(this.params, this.page);
+    },
+    // reset to fetch table data
+    resetList() {
+      this.page.pageNum = 1;
+      this.params = initParams(this.searchColumns);
+      this.fetchList(this.params, this.page);
+    },
+    // size change to fetch table data
+    pageSizeChange(prop) {
+      this.page.pageSize = prop;
+      this.fetchList(this.params, this.page);
+    },
+    // number change to fetch table data
+    pageNumberChange(prop) {
+      this.page.pageNum = prop;
+      this.fetchList(this.params, this.page);
+    },
+    // select row data
+    selectCurrentData(row) {
+      this.currentData = row;
+    },
+    // set row data highlight
+    setCurrentData(row) {
+      this.$refs.singleTable.setCurrentRow(row);
+    },
+    //
+    confirm() {
+      if (this.currentData) {
+        this.$emit("confirm", this.currentData);
+      }
+      this.setVisible(false);
+    },
+  },
+  created() {},
+  mounted() {},
+  destroyed() {},
+};
+</script>
+<template>
+  <el-dialog
+    :title="title"
+    :visible.sync="visible"
+    :width="width"
+    append-to-body
+    @open="beforeOpen"
+  >
+    <el-form :size="size" :inline="true" :model="params">
+      <el-form-item
+        v-for="(column, index) in searchColumns"
+        :key="index"
+        :label="column.title"
+      >
+        <el-input v-model="params[column.key]" @change="queryList"> </el-input>
+      </el-form-item>
+      <el-form-item>
+        <el-button icon="el-icon-refresh" @click="resetList"></el-button>
+      </el-form-item>
+    </el-form>
+    <el-table
+      v-loading="loading"
+      :data="data"
+      :size="size"
+      ref="singleTable"
+      height="45vh"
+      highlight-current-row
+      style="width: 100%; margin-bottom: 20px"
+      @row-click="selectCurrentData"
+    >
+      <el-table-column
+        v-for="(column, index) in tableColumns"
+        :key="index"
+        :prop="column.key"
+        :label="column.title"
+        :width="column.width"
+        show-overflow-tooltip
+      >
+      </el-table-column>
+    </el-table>
+    <div
+      style="display: flex; justify-content: space-between; align-items: center"
+    >
+      <p>
+        <span style="font-size: 12px">已选择 :</span>
+        <el-tag v-if="currentData" :size="size">{{
+          currentData[showKey]
+        }}</el-tag>
+        <span v-else>无</span>
+      </p>
+      <el-pagination
+        :layout="layout"
+        :total="page.total"
+        :page-sizes="pageSizes"
+        :page-size="page.pageSize"
+        :current-page="page.pageNum"
+        :small="size === 'mini'"
+        background
+        @size-change="pageSizeChange"
+        @current-change="pageNumberChange"
+      >
+      </el-pagination>
+    </div>
+    <div style="margin-top: 20px; text-align: right">
+      <el-button :size="size" @click="visible = false">取 消</el-button>
+      <el-button :size="size" type="primary" @click="confirm">确 定</el-button>
+    </div>
+  </el-dialog>
+</template>
+<style scoped></style>

+ 19 - 0
src/views/common-dialog/index.js

@@ -0,0 +1,19 @@
+// 员工
+import user from "./user.vue";
+// 组织
+import organization from "./organization.vue";
+// 部门
+import department from "./department.vue";
+// 供应商
+import supplier from "./supplier.vue";
+// 税率
+import tax from "./tax.vue";
+// 币种
+import currency from "./currency.vue";
+
+export const User = user;
+export const Organization = organization;
+export const Department = department;
+export const Supplier = supplier;
+export const Tax = tax;
+export const Currency = currency;

+ 198 - 0
src/views/common-dialog/organization.vue

@@ -0,0 +1,198 @@
+<script>
+import { initParams } from "./utils/init-something";
+import { list } from "./api/index";
+
+export default {
+  name: "OrganizationInputDialog",
+  props: ["title", "value"],
+  components: {},
+  data() {
+    const columns = [
+      {
+        key: "deptId",
+        title: "组织编码",
+        type: "Input",
+        search: true,
+      },
+      {
+        key: "deptName",
+        title: "组织名称",
+        type: "Input",
+        search: true,
+      },
+    ];
+    const initTableColumns = () => columns.filter((column) => column.key);
+    const initSearchColumns = () => columns.filter((column) => column.search);
+    return {
+      // global
+      size: "mini",
+      width: "50%",
+      page: { pageNum: 1, pageSize: 25, total: 0 },
+      pageSizes: [25, 50],
+      layout: "prev, pager, next, jumper",
+      api: "puOrg",
+      showKey: "deptName",
+      // dialog
+      visible: false,
+      loading: false,
+      // search
+      searchColumns: initSearchColumns(),
+      params: initParams(initSearchColumns()),
+      // table
+      tableColumns: initTableColumns(),
+      data: [],
+      currentData: null,
+    };
+  },
+  computed: {},
+  watch: {},
+  methods: {
+    // set dialog visible
+    setVisible(prop) {
+      this.visible = prop;
+    },
+    // do something before dialog open
+    beforeOpen() {
+      const { value } = this.$props;
+      this.params[this.showKey] = value;
+      this.fetchList(this.params, this.page);
+    },
+    // fetch table data
+    async fetchList(prop, page) {
+      try {
+        this.loading = true;
+        const { pageNum, pageSize } = page;
+        const { code, msg, rows, total } = await list(this.api, {
+          ...prop,
+          pageNum,
+          pageSize,
+        });
+        if (code === 200) {
+          this.data = rows;
+          this.page.total = total;
+          this.$notify.success({ title: msg });
+        } else {
+          this.$notify.warning({ title: msg });
+        }
+      } catch (err) {
+        this.$notify.error({ title: "error", message: err });
+      } finally {
+        this.loading = false;
+        this.setCurrentData(
+          this.data.find(
+            (column) => column[this.showKey] === this.currentData[this.showKey]
+          )
+        );
+      }
+    },
+    // setting up to fetch table data
+    queryList() {
+      this.fetchList(this.params, this.page);
+    },
+    // reset to fetch table data
+    resetList() {
+      this.page.pageNum = 1;
+      this.params = initParams(this.searchColumns);
+      this.fetchList(this.params, this.page);
+    },
+    // size change to fetch table data
+    pageSizeChange(prop) {
+      this.page.pageSize = prop;
+      this.fetchList(this.params, this.page);
+    },
+    // number change to fetch table data
+    pageNumberChange(prop) {
+      this.page.pageNum = prop;
+      this.fetchList(this.params, this.page);
+    },
+    // select row data
+    selectCurrentData(row) {
+      this.currentData = row;
+    },
+    // set row data highlight
+    setCurrentData(row) {
+      this.$refs.singleTable.setCurrentRow(row);
+    },
+    //
+    confirm() {
+      if (this.currentData) {
+        this.$emit("confirm", this.currentData);
+      }
+      this.setVisible(false);
+    },
+  },
+  created() {},
+  mounted() {},
+  destroyed() {},
+};
+</script>
+<template>
+  <el-dialog
+    :title="title"
+    :visible.sync="visible"
+    :width="width"
+    append-to-body
+    @open="beforeOpen"
+  >
+    <el-form :size="size" :inline="true" :model="params">
+      <el-form-item
+        v-for="(column, index) in searchColumns"
+        :key="index"
+        :label="column.title"
+      >
+        <el-input v-model="params[column.key]" @change="queryList"> </el-input>
+      </el-form-item>
+      <el-form-item>
+        <el-button icon="el-icon-refresh" @click="resetList"></el-button>
+      </el-form-item>
+    </el-form>
+    <el-table
+      v-loading="loading"
+      :data="data"
+      :size="size"
+      ref="singleTable"
+      height="45vh"
+      highlight-current-row
+      style="width: 100%; margin-bottom: 20px"
+      @row-click="selectCurrentData"
+    >
+      <el-table-column
+        v-for="(column, index) in tableColumns"
+        :key="index"
+        :prop="column.key"
+        :label="column.title"
+        :width="column.width"
+        show-overflow-tooltip
+      >
+      </el-table-column>
+    </el-table>
+    <div
+      style="display: flex; justify-content: space-between; align-items: center"
+    >
+      <p>
+        <span style="font-size: 12px">已选择 :</span>
+        <el-tag v-if="currentData" :size="size">{{
+          currentData[showKey]
+        }}</el-tag>
+        <span v-else>无</span>
+      </p>
+      <el-pagination
+        :layout="layout"
+        :total="page.total"
+        :page-sizes="pageSizes"
+        :page-size="page.pageSize"
+        :current-page="page.pageNum"
+        :small="size === 'mini'"
+        background
+        @size-change="pageSizeChange"
+        @current-change="pageNumberChange"
+      >
+      </el-pagination>
+    </div>
+    <div style="margin-top: 20px; text-align: right">
+      <el-button :size="size" @click="visible = false">取 消</el-button>
+      <el-button :size="size" type="primary" @click="confirm">确 定</el-button>
+    </div>
+  </el-dialog>
+</template>
+<style scoped></style>

+ 203 - 0
src/views/common-dialog/payment-plan.vue

@@ -0,0 +1,203 @@
+<script>
+import { initParams } from "./utils/init-something";
+import { list } from "./api/index";
+
+export default {
+  name: "PaymentPlanInputDialog",
+  props: ["title", "value"],
+  components: {},
+  data() {
+    const columns = [
+      {
+        key: "",
+        title: "付款协议名称",
+        type: "Input",
+        search: true,
+      },
+      {
+        key: "",
+        title: "付款协议编码",
+        type: "Input",
+        search: true,
+      },
+      {
+        key: "",
+        title: "管理组织",
+      },
+      {
+        key: "",
+        title: "有效期开始时间",
+      },
+      {
+        key: "",
+        title: "有效期结束时间",
+      },
+      {
+        key: "",
+        title: "说明",
+      },
+    ];
+    const initTableColumns = () => columns.filter((column) => column.key);
+    const initSearchColumns = () => columns.filter((column) => column.search);
+    return {
+      // global
+      size: "mini",
+      width: "50%",
+      page: { pageNum: 1, pageSize: 25, total: 0 },
+      pageSizes: [25, 50],
+      layout: "prev, pager, next, jumper",
+      api: "puTaxRate",
+      showKey: "mattaxesname",
+      // dialog
+      visible: false,
+      loading: false,
+      // search
+      searchColumns: initSearchColumns(),
+      params: initParams(initSearchColumns()),
+      // table
+      tableColumns: initTableColumns(),
+      data: [],
+      currentData: null,
+    };
+  },
+  computed: {},
+  watch: {},
+  methods: {
+    // set dialog visible
+    setVisible(prop) {
+      this.visible = prop;
+    },
+    // do something before dialog open
+    beforeOpen() {
+      const { value } = this.$props;
+      this.params.deptName = value;
+      this.fetchList(this.params, this.page);
+    },
+    // fetch table data
+    async fetchList(prop, page) {
+      try {
+        this.loading = true;
+        const { pageNum, pageSize } = page;
+        const { code, msg, rows, total } = await list(this.api, {
+          ...prop,
+          pageNum,
+          pageSize,
+        });
+        if (code === 200) {
+          this.data = rows;
+          this.page.total = total;
+          this.$notify.success({ title: msg });
+        } else {
+          this.$notify.warning({ title: msg });
+        }
+      } catch (err) {
+        this.$notify.error({ title: "error", message: err });
+      } finally {
+        this.loading = false;
+      }
+    },
+    // setting up to fetch table data
+    queryList() {
+      this.fetchList(this.params, this.page);
+    },
+    // reset to fetch table data
+    resetList() {
+      this.page.pageNum = 1;
+      this.params = initParams(this.searchColumns);
+      this.fetchList(this.params, this.page);
+    },
+    // size change to fetch table data
+    pageSizeChange(prop) {
+      this.page.pageSize = prop;
+      this.fetchList(this.params, this.page);
+    },
+    // number change to fetch table data
+    pageNumberChange(prop) {
+      this.page.pageNum = prop;
+      this.fetchList(this.params, this.page);
+    },
+    // select row data
+    selectCurrentData(row) {
+      this.currentData = row;
+    },
+    //
+    confirm() {
+      if (this.currentData) {
+        this.$emit("confirm", this.currentData);
+      }
+      this.setVisible(false);
+    },
+  },
+  created() {},
+  mounted() {},
+  destroyed() {},
+};
+</script>
+<template>
+  <el-dialog
+    :title="title"
+    :visible.sync="visible"
+    :width="width"
+    append-to-body
+    @open="beforeOpen"
+  >
+    <el-form :size="size" :inline="true" :model="params">
+      <el-form-item
+        v-for="(column, index) in searchColumns"
+        :key="index"
+        :label="column.title"
+      >
+        <el-input v-model="params[column.key]" @change="queryList"> </el-input>
+      </el-form-item>
+      <el-form-item>
+        <el-button icon="el-icon-refresh" @click="resetList"></el-button>
+      </el-form-item>
+    </el-form>
+    <el-table
+      v-loading="loading"
+      :data="data"
+      :size="size"
+      height="45vh"
+      style="width: 100%; margin-bottom: 20px"
+      @row-click="selectCurrentData"
+    >
+      <el-table-column
+        v-for="(column, index) in tableColumns"
+        :key="index"
+        :prop="column.key"
+        :label="column.title"
+        :width="column.width"
+        show-overflow-tooltip
+      >
+      </el-table-column>
+    </el-table>
+    <div
+      style="display: flex; justify-content: space-between; align-items: center"
+    >
+      <p>
+        <span style="font-size: 12px">已选择 :</span>
+        <el-tag v-if="currentData" :size="size">{{
+          currentData[showKey]
+        }}</el-tag>
+        <span v-else>无</span>
+      </p>
+      <el-pagination
+        :layout="layout"
+        :total="page.total"
+        :page-sizes="pageSizes"
+        :page-size="page.pageSize"
+        :current-page="page.pageNum"
+        :small="size === 'mini'"
+        background
+        @size-change="pageSizeChange"
+        @current-change="pageNumberChange"
+      >
+      </el-pagination>
+    </div>
+    <div style="margin-top: 20px; text-align: right">
+      <el-button :size="size" @click="visible = false">取 消</el-button>
+      <el-button :size="size" type="primary" @click="confirm">确 定</el-button>
+    </div>
+  </el-dialog>
+</template>
+<style scoped></style>

+ 198 - 0
src/views/common-dialog/supplier.vue

@@ -0,0 +1,198 @@
+<script>
+import { initParams } from "./utils/init-something";
+import { list } from "./api/index";
+
+export default {
+  name: "SupplierInputDialog",
+  props: ["title", "value"],
+  components: {},
+  data() {
+    const columns = [
+      {
+        key: "code",
+        title: "供应商编码",
+        type: "Input",
+        search: true,
+      },
+      {
+        key: "name",
+        title: "供应商名称",
+        type: "Input",
+        search: true,
+      },
+    ];
+    const initTableColumns = () => columns.filter((column) => column.key);
+    const initSearchColumns = () => columns.filter((column) => column.search);
+    return {
+      // global
+      size: "mini",
+      width: "50%",
+      page: { pageNum: 1, pageSize: 25, total: 0 },
+      pageSizes: [25, 50],
+      layout: "prev, pager, next, jumper",
+      api: "puSupplier",
+      showKey: "name",
+      // dialog
+      visible: false,
+      loading: false,
+      // search
+      searchColumns: initSearchColumns(),
+      params: initParams(initSearchColumns()),
+      // table
+      tableColumns: initTableColumns(),
+      data: [],
+      currentData: null,
+    };
+  },
+  computed: {},
+  watch: {},
+  methods: {
+    // set dialog visible
+    setVisible(prop) {
+      this.visible = prop;
+    },
+    // do something before dialog open
+    beforeOpen() {
+      const { value } = this.$props;
+      this.params[this.showKey] = value;
+      this.fetchList(this.params, this.page);
+    },
+    // fetch table data
+    async fetchList(prop, page) {
+      try {
+        this.loading = true;
+        const { pageNum, pageSize } = page;
+        const { code, msg, rows, total } = await list(this.api, {
+          ...prop,
+          pageNum,
+          pageSize,
+        });
+        if (code === 200) {
+          this.data = rows;
+          this.page.total = total;
+          this.$notify.success({ title: msg });
+        } else {
+          this.$notify.warning({ title: msg });
+        }
+      } catch (err) {
+        this.$notify.error({ title: "error", message: err });
+      } finally {
+        this.loading = false;
+        this.setCurrentData(
+          this.data.find(
+            (column) => column[this.showKey] === this.currentData[this.showKey]
+          )
+        );
+      }
+    },
+    // setting up to fetch table data
+    queryList() {
+      this.fetchList(this.params, this.page);
+    },
+    // reset to fetch table data
+    resetList() {
+      this.page.pageNum = 1;
+      this.params = initParams(this.searchColumns);
+      this.fetchList(this.params, this.page);
+    },
+    // size change to fetch table data
+    pageSizeChange(prop) {
+      this.page.pageSize = prop;
+      this.fetchList(this.params, this.page);
+    },
+    // number change to fetch table data
+    pageNumberChange(prop) {
+      this.page.pageNum = prop;
+      this.fetchList(this.params, this.page);
+    },
+    // select row data
+    selectCurrentData(row) {
+      this.currentData = row;
+    },
+    // set row data highlight
+    setCurrentData(row) {
+      this.$refs.singleTable.setCurrentRow(row);
+    },
+    //
+    confirm() {
+      if (this.currentData) {
+        this.$emit("confirm", this.currentData);
+      }
+      this.setVisible(false);
+    },
+  },
+  created() {},
+  mounted() {},
+  destroyed() {},
+};
+</script>
+<template>
+  <el-dialog
+    :title="title"
+    :visible.sync="visible"
+    :width="width"
+    append-to-body
+    @open="beforeOpen"
+  >
+    <el-form :size="size" :inline="true" :model="params">
+      <el-form-item
+        v-for="(column, index) in searchColumns"
+        :key="index"
+        :label="column.title"
+      >
+        <el-input v-model="params[column.key]" @change="queryList"> </el-input>
+      </el-form-item>
+      <el-form-item>
+        <el-button icon="el-icon-refresh" @click="resetList"></el-button>
+      </el-form-item>
+    </el-form>
+    <el-table
+      v-loading="loading"
+      :data="data"
+      :size="size"
+      ref="singleTable"
+      height="45vh"
+      highlight-current-row
+      style="width: 100%; margin-bottom: 20px"
+      @row-click="selectCurrentData"
+    >
+      <el-table-column
+        v-for="(column, index) in tableColumns"
+        :key="index"
+        :prop="column.key"
+        :label="column.title"
+        :width="column.width"
+        show-overflow-tooltip
+      >
+      </el-table-column>
+    </el-table>
+    <div
+      style="display: flex; justify-content: space-between; align-items: center"
+    >
+      <p>
+        <span style="font-size: 12px">已选择 :</span>
+        <el-tag v-if="currentData" :size="size">{{
+          currentData[showKey]
+        }}</el-tag>
+        <span v-else>无</span>
+      </p>
+      <el-pagination
+        :layout="layout"
+        :total="page.total"
+        :page-sizes="pageSizes"
+        :page-size="page.pageSize"
+        :current-page="page.pageNum"
+        :small="size === 'mini'"
+        background
+        @size-change="pageSizeChange"
+        @current-change="pageNumberChange"
+      >
+      </el-pagination>
+    </div>
+    <div style="margin-top: 20px; text-align: right">
+      <el-button :size="size" @click="visible = false">取 消</el-button>
+      <el-button :size="size" type="primary" @click="confirm">确 定</el-button>
+    </div>
+  </el-dialog>
+</template>
+<style scoped></style>

+ 198 - 0
src/views/common-dialog/tax.vue

@@ -0,0 +1,198 @@
+<script>
+import { initParams } from "./utils/init-something";
+import { list } from "./api/index";
+
+export default {
+  name: "TaxInputDialog",
+  props: ["title", "value"],
+  components: {},
+  data() {
+    const columns = [
+      {
+        key: "mattaxesname",
+        title: "税目税率名称",
+        type: "Input",
+        search: true,
+      },
+      {
+        key: "mattaxescode",
+        title: "税目税率编码",
+        type: "Input",
+        search: true,
+      },
+    ];
+    const initTableColumns = () => columns.filter((column) => column.key);
+    const initSearchColumns = () => columns.filter((column) => column.search);
+    return {
+      // global
+      size: "mini",
+      width: "50%",
+      page: { pageNum: 1, pageSize: 25, total: 0 },
+      pageSizes: [25, 50],
+      layout: "prev, pager, next, jumper",
+      api: "puTaxRate",
+      showKey: "mattaxesname",
+      // dialog
+      visible: false,
+      loading: false,
+      // search
+      searchColumns: initSearchColumns(),
+      params: initParams(initSearchColumns()),
+      // table
+      tableColumns: initTableColumns(),
+      data: [],
+      currentData: null,
+    };
+  },
+  computed: {},
+  watch: {},
+  methods: {
+    // set dialog visible
+    setVisible(prop) {
+      this.visible = prop;
+    },
+    // do something before dialog open
+    beforeOpen() {
+      const { value } = this.$props;
+      this.params[this.showKey] = value;
+      this.fetchList(this.params, this.page);
+    },
+    // fetch table data
+    async fetchList(prop, page) {
+      try {
+        this.loading = true;
+        const { pageNum, pageSize } = page;
+        const { code, msg, rows, total } = await list(this.api, {
+          ...prop,
+          pageNum,
+          pageSize,
+        });
+        if (code === 200) {
+          this.data = rows;
+          this.page.total = total;
+          this.$notify.success({ title: msg });
+        } else {
+          this.$notify.warning({ title: msg });
+        }
+      } catch (err) {
+        this.$notify.error({ title: "error", message: err });
+      } finally {
+        this.loading = false;
+        this.setCurrentData(
+          this.data.find(
+            (column) => column[this.showKey] === this.currentData[this.showKey]
+          )
+        );
+      }
+    },
+    // setting up to fetch table data
+    queryList() {
+      this.fetchList(this.params, this.page);
+    },
+    // reset to fetch table data
+    resetList() {
+      this.page.pageNum = 1;
+      this.params = initParams(this.searchColumns);
+      this.fetchList(this.params, this.page);
+    },
+    // size change to fetch table data
+    pageSizeChange(prop) {
+      this.page.pageSize = prop;
+      this.fetchList(this.params, this.page);
+    },
+    // number change to fetch table data
+    pageNumberChange(prop) {
+      this.page.pageNum = prop;
+      this.fetchList(this.params, this.page);
+    },
+    // select row data
+    selectCurrentData(row) {
+      this.currentData = row;
+    },
+    // set row data highlight
+    setCurrentData(row) {
+      this.$refs.singleTable.setCurrentRow(row);
+    },
+    //
+    confirm() {
+      if (this.currentData) {
+        this.$emit("confirm", this.currentData);
+      }
+      this.setVisible(false);
+    },
+  },
+  created() {},
+  mounted() {},
+  destroyed() {},
+};
+</script>
+<template>
+  <el-dialog
+    :title="title"
+    :visible.sync="visible"
+    :width="width"
+    append-to-body
+    @open="beforeOpen"
+  >
+    <el-form :size="size" :inline="true" :model="params">
+      <el-form-item
+        v-for="(column, index) in searchColumns"
+        :key="index"
+        :label="column.title"
+      >
+        <el-input v-model="params[column.key]" @change="queryList"> </el-input>
+      </el-form-item>
+      <el-form-item>
+        <el-button icon="el-icon-refresh" @click="resetList"></el-button>
+      </el-form-item>
+    </el-form>
+    <el-table
+      v-loading="loading"
+      :data="data"
+      :size="size"
+      ref="singleTable"
+      height="45vh"
+      highlight-current-row
+      style="width: 100%; margin-bottom: 20px"
+      @row-click="selectCurrentData"
+    >
+      <el-table-column
+        v-for="(column, index) in tableColumns"
+        :key="index"
+        :prop="column.key"
+        :label="column.title"
+        :width="column.width"
+        show-overflow-tooltip
+      >
+      </el-table-column>
+    </el-table>
+    <div
+      style="display: flex; justify-content: space-between; align-items: center"
+    >
+      <p>
+        <span style="font-size: 12px">已选择 :</span>
+        <el-tag v-if="currentData" :size="size">{{
+          currentData[showKey]
+        }}</el-tag>
+        <span v-else>无</span>
+      </p>
+      <el-pagination
+        :layout="layout"
+        :total="page.total"
+        :page-sizes="pageSizes"
+        :page-size="page.pageSize"
+        :current-page="page.pageNum"
+        :small="size === 'mini'"
+        background
+        @size-change="pageSizeChange"
+        @current-change="pageNumberChange"
+      >
+      </el-pagination>
+    </div>
+    <div style="margin-top: 20px; text-align: right">
+      <el-button :size="size" @click="visible = false">取 消</el-button>
+      <el-button :size="size" type="primary" @click="confirm">确 定</el-button>
+    </div>
+  </el-dialog>
+</template>
+<style scoped></style>

+ 226 - 0
src/views/common-dialog/user.vue

@@ -0,0 +1,226 @@
+<script>
+import { initParams } from "./utils/init-something";
+import { list } from "./api/index";
+
+export default {
+  name: "UserInputDialog",
+  props: ["title"],
+  components: {},
+  data() {
+    const columns = [
+      {
+        key: "userName",
+        title: "员工姓名",
+        type: "Input",
+        search: true,
+      },
+      {
+        key: "userId",
+        title: "员工编码",
+        type: "Input",
+        search: true,
+      },
+      {
+        key: "orgName",
+        title: "任职(兼职)组织",
+        type: "Input",
+        width: 200,
+      },
+      {
+        key: "deptName",
+        title: "部门",
+        type: "Input",
+        width: 200,
+      },
+      {
+        key: "",
+        title: "岗位",
+        type: "Input",
+      },
+      {
+        key: "email",
+        title: "邮箱",
+        type: "Input",
+        width: 200,
+      },
+      {
+        key: "",
+        title: "职位",
+        type: "Input",
+      },
+    ];
+    const initTableColumns = () => columns.filter((column) => column.key);
+    const initSearchColumns = () => columns.filter((column) => column.search);
+    return {
+      // global
+      size: "mini",
+      width: "50%",
+      page: { pageNum: 1, pageSize: 25, total: 0 },
+      pageSizes: [25, 50],
+      layout: "prev, pager, next, jumper",
+      api: "puPersonnel",
+      showKey: "userName",
+      // dialog
+      visible: false,
+      loading: false,
+      // search
+      searchColumns: initSearchColumns(),
+      params: initParams(initSearchColumns()),
+      // table
+      tableColumns: initTableColumns(),
+      data: [],
+      currentData: null,
+    };
+  },
+  computed: {},
+  watch: {},
+  methods: {
+    // set dialog visible
+    setVisible(prop) {
+      this.visible = prop;
+    },
+    // do something before dialog open
+    beforeOpen() {
+      const { value } = this.$props;
+      this.params[this.showKey] = value;
+      this.fetchList(this.params, this.page);
+    },
+    // fetch table data
+    async fetchList(prop, page) {
+      try {
+        this.loading = true;
+        const { pageNum, pageSize } = page;
+        const { code, msg, rows, total } = await list(this.api, {
+          ...prop,
+          pageNum,
+          pageSize,
+        });
+        if (code === 200) {
+          this.data = rows;
+          this.page.total = total;
+          this.$notify.success({ title: msg });
+        } else {
+          this.$notify.warning({ title: msg });
+        }
+      } catch (err) {
+        this.$notify.error({ title: "error", message: err });
+      } finally {
+        this.loading = false;
+        this.setCurrentData(
+          this.data.find(
+            (column) => column[this.showKey] === this.currentData[this.showKey]
+          )
+        );
+      }
+    },
+    // setting up to fetch table data
+    queryList() {
+      this.fetchList(this.params, this.page);
+    },
+    // reset to fetch table data
+    resetList() {
+      this.page.pageNum = 1;
+      this.params = initParams(this.searchColumns);
+      this.fetchList(this.params, this.page);
+    },
+    // size change to fetch table data
+    pageSizeChange(prop) {
+      this.page.pageSize = prop;
+      this.fetchList(this.params, this.page);
+    },
+    // number change to fetch table data
+    pageNumberChange(prop) {
+      this.page.pageNum = prop;
+      this.fetchList(this.params, this.page);
+    },
+    // select row data
+    selectCurrentData(row) {
+      this.currentData = row;
+    },
+    // set row data highlight
+    setCurrentData(row) {
+      this.$refs.singleTable.setCurrentRow(row);
+    },
+    //
+    confirm() {
+      if (this.currentData) {
+        this.$emit("confirm", this.currentData);
+      }
+      this.setVisible(false);
+    },
+  },
+  created() {},
+  mounted() {},
+  destroyed() {},
+};
+</script>
+<template>
+  <el-dialog
+    :title="title"
+    :visible.sync="visible"
+    :width="width"
+    append-to-body
+    @open="beforeOpen"
+  >
+    <el-form :size="size" :inline="true" :model="params">
+      <el-form-item
+        v-for="(column, index) in searchColumns"
+        :key="index"
+        :label="column.title"
+      >
+        <el-input v-model="params[column.key]" @change="queryList"> </el-input>
+      </el-form-item>
+      <el-form-item>
+        <el-button icon="el-icon-refresh" @click="resetList"></el-button>
+      </el-form-item>
+    </el-form>
+    <el-table
+      v-loading="loading"
+      :data="data"
+      :size="size"
+      ref="singleTable"
+      height="45vh"
+      highlight-current-row
+      style="width: 100%; margin-bottom: 20px"
+      @row-click="selectCurrentData"
+    >
+      <el-table-column
+        v-for="(column, index) in tableColumns"
+        :key="index"
+        :prop="column.key"
+        :label="column.title"
+        :width="column.width"
+        show-overflow-tooltip
+      >
+      </el-table-column>
+    </el-table>
+    <div
+      style="display: flex; justify-content: space-between; align-items: center"
+    >
+      <p>
+        <span style="font-size: 12px">已选择 :</span>
+        <el-tag v-if="currentData" :size="size">{{
+          currentData[showKey]
+        }}</el-tag>
+        <span v-else>无</span>
+      </p>
+      <el-pagination
+        :layout="layout"
+        :total="page.total"
+        :page-sizes="pageSizes"
+        :page-size="page.pageSize"
+        :current-page="page.pageNum"
+        :small="size === 'mini'"
+        background
+        @size-change="pageSizeChange"
+        @current-change="pageNumberChange"
+      >
+      </el-pagination>
+    </div>
+    <div style="margin-top: 20px; text-align: right">
+      <el-button :size="size" @click="visible = false">取 消</el-button>
+      <el-button :size="size" type="primary" @click="confirm">确 定</el-button>
+    </div>
+  </el-dialog>
+</template>
+<style scoped></style>

+ 2 - 0
src/views/common-dialog/utils/data-transform.js

@@ -0,0 +1,2 @@
+export const arr2obj = (data, keyName, valueName) =>
+  Object.fromEntries(data.map((item) => [item[keyName], item[valueName]]));

+ 18 - 0
src/views/common-dialog/utils/init-something.js

@@ -0,0 +1,18 @@
+import { arr2obj } from "./data-transform";
+
+export const initParams = (arr) => arr2obj(arr, "key", "value");
+
+export const initComponents = (arr) =>
+  arr2obj(
+    arr
+      .filter((column) => column.config && column.config.componentName)
+      .map((column) => ({
+        name: column.config.componentName,
+        function: () =>
+          import(
+            `@/views/common-dialog/${column.config.componentName.toLocaleLowerCase()}.vue`
+          ),
+      })),
+    "name",
+    "function"
+  );

+ 138 - 206
src/views/purchase/purchase-contract/add-purchase-contract.vue

@@ -1,192 +1,25 @@
 <script>
+import { add } from "@/api/business/purchase/purchase-contract";
+import { arr2obj } from "./hooks";
+import {
+  initDicts,
+  initRules,
+  initParams,
+  initColumns,
+  initTabColumns,
+  initComponents,
+} from "./config/add";
+// import { initComponents } from "@/views/common-dialog/utils/init-something";
+
 export default {
   name: "AddPurchaseContractDrawer",
+  components: initComponents(initColumns()),
+  dicts: initDicts(),
   data() {
-    const arr2Obj = function (data, keyName, valueName) {
-      return Object.fromEntries(
-        data.map((item) => [item[keyName], item[valueName]])
-      );
-    };
-    const columns = [
-      { key: "puOrg", title: "采购组织", type: "TagSelect", require: true },
-      { key: "code", title: "合同编码", type: "Input" },
-      { key: "contractName", title: "合同名称", type: "Input", require: true },
-      { key: "supplier", title: "供应商", type: "TagSelect", require: true },
-      { key: "contractType", title: "合同类型", type: "Select", require: true },
-      { key: "puDept", title: "采购部门", type: "TagSelect", require: true },
-      { key: "buyer", title: "采购员", type: "TagSelect" },
-      { key: "source", title: "合同来源", type: "Select" },
-      {
-        key: "signDate",
-        title: "合同签订日期",
-        type: "DatePicker",
-        require: true,
-      },
-      {
-        key: "effectiveDate",
-        title: "合同生效日期",
-        type: "DatePicker",
-        require: true,
-      },
-      { key: "endDate", title: "合同终止日期", type: "DatePicker" },
-      { key: "externalContract", title: "外部合同号", type: "Input" },
-      { key: "refusalReasons", title: "拒绝理由", type: "Input" },
-      { key: "enquiryCode", title: "询价单号", type: "Input" },
-      { key: "externalFile", title: "对外附件", type: "Upload", span: 24 },
-      { key: "puFile", title: "采购商盖章合同附件", type: "Upload", span: 24 },
-      {
-        key: "supplierFile",
-        title: "供应商盖章合同附件",
-        type: "Upload",
-        span: 24,
-      },
-      { key: "projectName", title: "项目名称", type: "TagSelect" },
-      { key: "projectCode", title: "项目编号", type: "Input" },
-      { key: "area", title: "区域", type: "Input" },
-      { key: "consigneePhone", title: "收货人联系方式", type: "Input" },
-      { key: "paymentAgreement", title: "付款协议", type: "TagSelect" },
-      { key: "currency", title: "币种", type: "TagSelect", require: true },
-      { key: "taxPrice", title: "价税合计", type: "InputNumber" },
-      { key: "guaranteePeriod", title: "质保期", type: "Input" },
-
-      // { key: "lastPuMoney", title: "上年度采购额" },
-      // { key: "buyerName", title: "采购员名称" },
-      // { key: "supplierName", title: "供应商名称" },
-      // { key: "puMoneyYear", title: "本年度采购额" },
-      // { key: "puDeptName", title: "采购部门名称" },
-      // { key: "supplierTier", title: "供应商层级" },
-      // { key: "grossRateAverage", title: "平均毛利率" },
-      // { key: "approveFlow", title: "审批流程" },
-      // { key: "consumableClass", title: "耗材类别" },
-      // { key: "brandGrossRate", title: "同类品牌及毛利率" },
-      // { key: "contractFormat", title: "合同格式" },
-      // { key: "productName", title: "产品类别&名称" },
-      // { key: "invoiceTax", title: "发票税率" },
-      // { key: "emergencyDegree", title: "紧急程度" },
-      // { key: "project", title: "项目医院" },
-      // { key: "deliveryType", title: "交货方式" },
-      // { key: "contractPartyc", title: "合同丙方" },
-      // { key: "contractPartycName", title: "合同丙方名称" },
-      // { key: "guaranteePeriodEnd", title: "质保期限" },
-      // { key: "freightMethods", title: "运费承担方式" },
-      // { key: "isTarget", title: "是否有指标" },
-      // { key: "contractTarget", title: "合同指标" },
-      // { key: "exemptionPostageCondtion", title: "包邮条件" },
-      // { key: "isRebate", title: "是否有返利" },
-      // { key: "rebatePolicy", title: "返利政策" },
-      // { key: "rollbackPolicy", title: "退换货政策" },
-      // { key: "contractContent", title: "合同主要内容" },
-      // { key: "currencyName", title: "币种名称" },
-      // { key: "tenantId", title: "租户号" },
-      // { key: "revision", title: "乐观锁" },
-      // { key: "createByName", title: "创建人" },
-      // { key: "updateByName", title: "创建人名称" },
-      // { key: "delFlag", title: "删除标记" },
-    ];
-    const initColumns = () =>
-      columns.map((column) => {
-        const clearable = column.clearable || true;
-        if (column.type === "InputNumber") {
-          return {
-            ...column,
-            clearable,
-            config: { controlsPosition: "right" },
-          };
-        }
-        if (column.type === "DatePicker") {
-          return {
-            ...column,
-            clearable,
-            config: { type: "date" },
-          };
-        }
-        return {
-          ...column,
-          clearable,
-        };
-      });
-    const initParams = () => arr2Obj(initColumns(), "key", "value");
-    const tabColumns = [
-      {
-        title: "物料基本信息",
-        key: "first",
-        tableColumns: [
-          { title: "序号", key: "" },
-          { title: "赠品", key: "" },
-          { title: "物料编码", key: "" },
-          { title: "物料名称", key: "" },
-          { title: "规格", key: "" },
-          { title: "生产厂家", key: "" },
-          { title: "收货客户", key: "" },
-          { title: "品牌", key: "" },
-          { title: "采购数量", key: "" },
-          { title: "采购单位", key: "" },
-          { title: "计价数量", key: "" },
-          { title: "税率%", key: "" },
-          { title: "含税单价", key: "" },
-          { title: "含税金额合计", key: "" },
-          { title: "价格有效期(起)", key: "" },
-          { title: "计划到货日期", key: "" },
-          { title: "来源类型", key: "" },
-          { title: "来源单号", key: "" },
-          { title: "需求单号", key: "" },
-          { title: "备注", key: "" },
-        ],
-      },
-      {
-        title: "合同条款",
-        key: "second",
-        tableColumns: [
-          { title: "序号", key: "" },
-          { title: "条款编码", key: "" },
-          { title: "条款名称", key: "" },
-          { title: "条款内容", key: "" },
-          { title: "变量序号", key: "" },
-          { title: "变量内容", key: "" },
-          { title: "备注", key: "" },
-        ],
-      },
-      {
-        title: "合同费用",
-        key: "third",
-        tableColumns: [
-          { title: "序号", key: "" },
-          { title: "费用编码", key: "" },
-          { title: "费用名称", key: "" },
-          { title: "费用金额", key: "" },
-          { title: "备注", key: "" },
-        ],
-      },
-      {
-        title: "付款协议信息",
-        key: "fourth",
-        tableColumns: [
-          { title: "序号", key: "" },
-          { title: "付款阶段", key: "" },
-          { title: "是否预付款", key: "" },
-          { title: "是否质保金", key: "" },
-          { title: "结算方式", key: "" },
-          { title: "付款起点", key: "" },
-          { title: "付款金额", key: "" },
-          { title: "付款比例%", key: "" },
-          { title: "账期天数", key: "" },
-          { title: "备注", key: "" },
-        ],
-      },
-      {
-        title: "合同执行组织范围",
-        key: "fifth",
-        tableColumns: [
-          { title: "序号", key: "" },
-          { title: "组织名称", key: "" },
-          { title: "组织编码", key: "" },
-        ],
-      },
-    ];
-    const initTabColumns = () => tabColumns;
     return {
-      visible: false,
+      visible: true,
       columns: initColumns(),
+      rules: initRules(),
       params: initParams(),
       options: [
         {
@@ -219,17 +52,76 @@ export default {
         fourth: [],
         fifth: [],
       },
+      currentComponent: { name: "", title: "", value: "", row: {} },
     };
   },
   computed: {},
   watch: {},
   methods: {
+    beforeOpen() {
+      const { deptName, nickName, orgName } = this.$store.state.user;
+      this.params.puOrg = orgName;
+      this.params.buyer = nickName;
+      this.params.puDept = deptName;
+    },
     setVisible(prop) {
       this.visible = prop;
     },
+    cancel() {
+      this.setVisible(false);
+      this.params = arr2obj(this.columns, "key", "value");
+    },
+    sava() {
+      this.setVisible(false);
+    },
+    async submitSava() {
+      console.log(this.params);
+      return;
+      try {
+        const res = await add(this.params);
+        console.log("res", res);
+      } catch (err) {
+        this.$notify.error({ title: "error", message: err });
+      } finally {
+        this.setVisible(false);
+      }
+    },
+    openAsyncInputDialog(prop, type) {
+      try {
+        const {
+          key,
+          title,
+          config: { componentName },
+        } = prop;
+        this.currentComponent.row = prop;
+        this.currentComponent.title = title;
+        this.currentComponent.name = componentName;
+        if (type === "change") {
+          this.currentComponent.value = this.params[key];
+        }
+        if (type === "click") {
+          this.currentComponent.value = "";
+        }
+        this.$nextTick(() => {
+          const { setVisible } = this.$refs[componentName];
+          setVisible(true);
+        });
+      } catch (err) {
+        this.$notify.error({ title: "error", message: err });
+      } finally {
+      }
+    },
+    updateParams(prop) {
+      const {
+        config: { dataMapping },
+      } = this.currentComponent.row;
+      for (let key in dataMapping) {
+        this.params[key] = prop[dataMapping[key]];
+      }
+    },
   },
   created() {
-    console.log(this.params, this.columns);
+    // console.log("this,", initComponents(initColumns()));
   },
   mounted() {},
   destroyed() {},
@@ -237,12 +129,11 @@ export default {
 </script>
 <template>
   <el-drawer
-    title="我是标题"
     direction="btt"
     size="100%"
     :with-header="false"
     :visible.sync="visible"
-    :before-close="handleClose"
+    @open="beforeOpen"
   >
     <el-card
       :body-style="{
@@ -262,38 +153,69 @@ export default {
       >
         <h3>新增</h3>
         <div style="text-align: right">
-          <el-button size="mini" @click="setVisible(false)">取消</el-button>
-          <el-button size="mini" type="info" @click="setVisible(false)"
-            >保存并新增</el-button
-          >
-          <el-button size="mini" type="danger" @click="setVisible(false)"
-            >保存</el-button
-          >
+          <el-button size="mini" @click="cancel">取消</el-button>
+          <el-button size="mini" type="danger" @click="sava">保存</el-button>
+          <el-button size="mini" type="info" @click="submitSava">
+            保存并新增
+          </el-button>
         </div>
       </div>
+      <component
+        v-if="currentComponent.name"
+        :is="currentComponent.name"
+        :ref="currentComponent.name"
+        :title="currentComponent.title"
+        :value="currentComponent.value"
+        @confirm="updateParams"
+      ></component>
       <el-row>
         <el-form
           size="mini"
           label-position="right"
-          label-width="150px"
+          label-width="135px"
           :model="params"
+          :rules="rules"
         >
           <el-col
             v-for="(column, index) in columns"
             :key="index"
-            :span="column.span || 8"
+            :span="column.span || 6"
           >
-            <el-form-item
-              :prop="column.key"
-              :label="column.title"
-              :required="column.required"
-            >
+            <el-form-item :prop="column.key" :label="column.title">
               <el-input
                 v-if="column.type === 'Input'"
                 v-model="params[column.key]"
                 :placeholder="column.placeholder"
                 :clearable="column.clearable"
-                style="width: 90%"
+                :disabled="column.disabled"
+                style="width: 100%"
+              ></el-input>
+              <el-input
+                v-if="column.type === 'InputDialog'"
+                v-model="params[column.key]"
+                :placeholder="column.placeholder"
+                :clearable="column.clearable"
+                :disabled="column.disabled"
+                style="width: 100%"
+                @blur="openAsyncInputDialog(column, 'change')"
+                @change="openAsyncInputDialog(column, 'change')"
+              >
+                <template #suffix>
+                  <el-icon
+                    class="el-icon-s-operation"
+                    style="cursor: pointer"
+                    @click.native.stop="openAsyncInputDialog(column, 'click')"
+                  ></el-icon>
+                </template>
+              </el-input>
+              <el-input
+                v-if="column.type === 'Textarea'"
+                v-model="params[column.key]"
+                type="textarea"
+                :placeholder="column.placeholder"
+                :clearable="column.clearable"
+                :disabled="column.disabled"
+                style="width: 100%"
               ></el-input>
               <el-input-number
                 v-if="column.type === 'InputNumber'"
@@ -301,17 +223,19 @@ export default {
                 :controls-position="column.config.controlsPosition"
                 :placeholder="column.placeholder"
                 :clearable="column.clearable"
-                style="width: 90%"
+                :disabled="column.disabled"
+                style="width: 100%"
               ></el-input-number>
               <el-select
                 v-if="column.type === 'Select'"
                 v-model="params[column.key]"
                 :placeholder="column.placeholder"
                 :clearable="column.clearable"
-                style="width: 90%"
+                :disabled="column.disabled"
+                style="width: 100%"
               >
                 <el-option
-                  v-for="item in options"
+                  v-for="item in dict.type[column.config.optionsName]"
                   :key="item.value"
                   :label="item.label"
                   :value="item.value"
@@ -326,7 +250,8 @@ export default {
                 collapse-tags
                 :placeholder="column.placeholder"
                 :clearable="column.clearable"
-                style="width: 90%"
+                :disabled="column.disabled"
+                style="width: 100%"
               >
                 <template #prefix>
                   <el-icon
@@ -349,13 +274,15 @@ export default {
                 :type="column.config.type"
                 :placeholder="column.placeholder"
                 :clearable="column.clearable"
+                :disabled="column.disabled"
                 :picker-options="column.pickerOptions"
-                style="width: 90%"
+                style="width: 100%"
               >
               </el-date-picker>
               <el-upload
                 v-if="column.type === 'Upload'"
                 :file-list="params[column.key]"
+                :disabled="column.disabled"
                 drag
                 action="https://jsonplaceholder.typicode.com/posts/"
                 multiple
@@ -378,6 +305,7 @@ export default {
         padding: '20px',
         display: 'flex',
         'flex-wrap': 'wrap',
+        position: 'relative',
       }"
       style="margin: 10px"
     >
@@ -394,11 +322,15 @@ export default {
               :key="cIndex"
               :prop="cColumn.key"
               :label="cColumn.title"
+              :width="cColumn.width"
             >
             </el-table-column>
           </el-table>
         </el-tab-pane>
       </el-tabs>
+      <el-row style="position: absolute; top: 20px; right: 20px">
+        <el-button size="mini">增行</el-button>
+      </el-row>
     </el-card>
   </el-drawer>
 </template>

+ 442 - 0
src/views/purchase/purchase-contract/config/add.js

@@ -0,0 +1,442 @@
+import { arr2obj } from "../hooks";
+
+const columns = [
+  {
+    key: "puOrg",
+    title: "采购组织",
+    type: "InputDialog",
+    config: {
+      componentName: "Organization",
+      dataMapping: { puOrg: "deptName" },
+    },
+    require: true,
+  },
+  { key: "code", title: "合同编码", type: "Input" },
+  {
+    key: "lastPuMoney",
+    title: "上年度采购额",
+    type: "Input",
+    require: true,
+  },
+  {
+    key: "buyer",
+    title: "采购员",
+    type: "InputDialog",
+    config: {
+      componentName: "User",
+      dataMapping: {
+        buyer: "userName",
+        puDept: "deptName",
+      },
+    },
+    require: true,
+  },
+  {
+    key: "supplier",
+    title: "供应商",
+    type: "InputDialog",
+    config: {
+      componentName: "Supplier",
+      dataMapping: { supplier: "name" },
+    },
+    require: true,
+  },
+  {
+    key: "contractType",
+    title: "合同类型",
+    type: "Select",
+    require: true,
+    config: {
+      optionsName: "purchase_contract_contract_type",
+    },
+  },
+  {
+    key: "puMoneyYear",
+    title: "本年度采购额",
+    type: "Input",
+    require: true,
+  },
+  {
+    key: "puDept",
+    title: "采购部门",
+    type: "InputDialog",
+    config: { componentName: "Department" },
+    require: true,
+  },
+  {
+    key: "supplierTier",
+    title: "供应商层级",
+    type: "Select",
+    require: true,
+    config: {
+      optionsName: "purchase_contract_supplier_tier",
+    },
+  },
+  { key: "contractName", title: "合同名称", type: "Input", require: true },
+  {
+    key: "grossRateAverage",
+    title: "平均毛利率",
+    type: "Input",
+    require: true,
+  },
+  {
+    key: "approveFlow",
+    title: "审批流程",
+    type: "Select",
+    require: true,
+    config: {
+      optionsName: "purchase_contract_approve_flow",
+    },
+  },
+  {
+    key: "consumableClass",
+    title: "耗材类别",
+    type: "Select",
+    require: true,
+    config: {
+      optionsName: "purchase_contract_consumable_class",
+    },
+  },
+  {
+    key: "effectiveDate",
+    title: "合同生效日期",
+    type: "DatePicker",
+    require: true,
+    config: { type: "date" },
+  },
+  {
+    key: "brandGrossRate",
+    title: "同类品牌及毛利率",
+    type: "Input",
+    require: true,
+  },
+  {
+    key: "contractFormat",
+    title: "合同格式",
+    type: "Input",
+    require: true,
+  },
+  {
+    key: "productName",
+    title: "产品类别&名称",
+    type: "Input",
+    require: true,
+  },
+  {
+    key: "endDate",
+    title: "合同终止日期",
+    type: "DatePicker",
+    require: true,
+    config: { type: "date" },
+  },
+  {
+    key: "invoiceTax",
+    title: "发票税率",
+    type: "InputDialog",
+    config: {
+      componentName: "Tax",
+      dataMapping: {
+        invoiceTax: "mattaxesname",
+      },
+    },
+    require: true,
+  },
+  {
+    key: "emergencyDegree",
+    title: "紧急程度",
+    type: "Select",
+    require: true,
+    config: {
+      optionsName: "purchase_contract_emergency_degree",
+    },
+  },
+  { key: "project", title: "项目医院", type: "Input", require: true },
+  {
+    key: "signDate",
+    title: "合同签订日期",
+    type: "DatePicker",
+    require: true,
+    config: { type: "date" },
+  },
+  {
+    key: "deliveryType",
+    title: "交货方式",
+    type: "Select",
+    config: {
+      optionsName: "purchase_contract_delivery_type",
+    },
+  },
+  {
+    key: "source",
+    title: "合同来源",
+    type: "Input",
+    value: "自制",
+    disabled: true,
+  },
+  {
+    key: "contractPartyc",
+    title: "合同丙方",
+    type: "InputDialog",
+    config: {
+      componentName: "Supplier",
+      dataMapping: {
+        contractPartyc: "name",
+      },
+    },
+  },
+  {
+    key: "guaranteePeriodEnd",
+    title: "质保期限",
+    type: "Input",
+    require: true,
+  },
+  {
+    key: "freightMethods",
+    title: "运费承担方式",
+    type: "Select",
+    config: {
+      optionsName: "purchase_contract_freight_methods",
+    },
+  },
+  {
+    key: "signDate",
+    title: "合同创建时间",
+    type: "DatePicker",
+    disabled: true,
+    config: { type: "date" },
+  },
+  {
+    key: "isTarget",
+    title: "是否有指标",
+    type: "Select",
+    require: true,
+    config: {
+      optionsName: "purchase_contract_is_target",
+    },
+  },
+  {
+    key: "contractTarget",
+    title: "合同指标",
+    type: "Input",
+    require: true,
+    placeholder: '当【是否有指标】="有"时,必填',
+  },
+  {
+    key: "exemptionPostageCondtion",
+    title: "包邮条件",
+    type: "Input",
+    placeholder:
+      "当运费承担方式为供应商有条件承担时,该字段必填,填写要求,写明什么条件下供应商承担全部,什么条件下我方承担,什么条件下分别承担",
+    span: 12,
+  },
+  {
+    key: "isRebate",
+    title: "是否有返利",
+    type: "Select",
+    require: true,
+    config: {
+      optionsName: "purchase_contract_is_rebate",
+    },
+  },
+  {
+    key: "rebatePolicy",
+    title: "返利政策",
+    type: "Input",
+    placeholder: '当【是否有返利】="有"时,必填',
+    span: 18,
+  },
+  { key: "externalContract", title: "外部合同号", type: "Input" },
+  {
+    key: "rollbackPolicy",
+    title: "退换货政策",
+    type: "Input",
+    require: true,
+  },
+  {
+    key: "contractContent",
+    title: "合同主要内容",
+    type: "Textarea",
+    require: true,
+    span: 24,
+  },
+  { key: "refusalReasons", title: "拒绝理由", type: "Input", span: 24 },
+  { key: "enquiryCode", title: "询价单号", type: "Input" },
+  { key: "externalFile", title: "对外附件", type: "Upload", span: 24 },
+  { key: "puFile", title: "采购商盖章合同附件", type: "Upload", span: 24 },
+  {
+    key: "supplierFile",
+    title: "供应商盖章合同附件",
+    type: "Upload",
+    span: 24,
+  },
+  { key: "projectCode", title: "项目编号", type: "Input" },
+  { key: "projectName", title: "项目名称", type: "Input" },
+  { key: "area", title: "区域", type: "Input" },
+  { key: "consigneePhone", title: "收货人联系方式", type: "Input" },
+  {
+    key: "paymentAgreement",
+    title: "付款协议",
+    type: "InputDialog",
+    config: {
+      componentName: "PaymentPlan",
+      dataMapping: {
+        buyer: "userName",
+        puDept: "deptName",
+      },
+    },
+    require: true,
+  },
+  {
+    key: "taxPrice",
+    title: "价税合计",
+    type: "InputNumber",
+    config: { controlsPosition: "right" },
+  },
+  {
+    key: "currency",
+    title: "币种",
+    type: "InputDialog",
+    config: {
+      componentName: "Currency",
+      dataMapping: {
+        currency: "name",
+      },
+    },
+    require: true,
+  },
+  { key: "guaranteePeriod", title: "质保期", type: "Input" },
+
+  // { key: "buyerName", title: "采购员名称" },
+  // { key: "supplierName", title: "供应商名称" },
+
+  // { key: "puDeptName", title: "采购部门名称" },
+
+  // { key: "contractPartycName", title: "合同丙方名称" },
+
+  // { key: "currencyName", title: "币种名称" },
+  // { key: "tenantId", title: "租户号" },
+  // { key: "revision", title: "乐观锁" },
+  // { key: "createByName", title: "创建人" },
+  // { key: "updateByName", title: "创建人名称" },
+  // { key: "delFlag", title: "删除标记" },
+];
+
+export const initColumns = () => columns;
+
+export const initDicts = () =>
+  initColumns()
+    .filter((column) => column.type === "Select")
+    .map((column) => column.config.optionsName);
+
+export const initRules = () => {
+  const rules = {};
+  initColumns()
+    .filter((column) => column.require)
+    .forEach((column) => {
+      const message = `${column.title}不能为空`;
+      rules[column.key] = [
+        { required: true, message: message, trigger: "change" },
+      ];
+    });
+  return rules;
+};
+
+export const initParams = () => arr2obj(initColumns(), "key", "value");
+
+const tabColumns = [
+  {
+    title: "物料基本信息",
+    key: "first",
+    tableColumns: [
+      { title: "序号", key: "" },
+      { title: "赠品", key: "" },
+      { title: "物料编码", key: "" },
+      { title: "物料名称", key: "" },
+      { title: "规格", key: "" },
+      { title: "生产厂家", key: "" },
+      { title: "收货客户", key: "" },
+      { title: "品牌", key: "" },
+      { title: "采购数量", key: "" },
+      { title: "采购单位", key: "" },
+      { title: "计价数量", key: "" },
+      { title: "税率%", key: "" },
+      { title: "含税单价", key: "" },
+      { title: "含税金额合计", key: "", width: 150 },
+      { title: "价格有效期(起)", key: "", width: 150 },
+      { title: "计划到货日期", key: "", width: 150 },
+      { title: "来源类型", key: "" },
+      { title: "来源单号", key: "" },
+      { title: "需求单号", key: "" },
+      { title: "备注", key: "" },
+    ],
+  },
+  {
+    title: "合同条款",
+    key: "second",
+    tableColumns: [
+      { title: "序号", key: "" },
+      { title: "条款编码", key: "" },
+      { title: "条款名称", key: "" },
+      { title: "条款内容", key: "" },
+      { title: "变量序号", key: "" },
+      { title: "变量内容", key: "" },
+      { title: "备注", key: "" },
+    ],
+  },
+  {
+    title: "合同费用",
+    key: "third",
+    tableColumns: [
+      { title: "序号", key: "" },
+      { title: "费用编码", key: "" },
+      { title: "费用名称", key: "" },
+      { title: "费用金额", key: "" },
+      { title: "备注", key: "" },
+    ],
+  },
+  {
+    title: "付款协议信息",
+    key: "fourth",
+    tableColumns: [
+      { title: "序号", key: "" },
+      { title: "付款阶段", key: "" },
+      { title: "是否预付款", key: "" },
+      { title: "是否质保金", key: "" },
+      { title: "结算方式", key: "" },
+      { title: "付款起点", key: "" },
+      { title: "付款金额", key: "" },
+      { title: "付款比例%", key: "" },
+      { title: "账期天数", key: "" },
+      { title: "备注", key: "" },
+    ],
+  },
+  {
+    title: "合同执行组织范围",
+    key: "fifth",
+    tableColumns: [
+      { title: "序号", key: "" },
+      { title: "组织名称", key: "" },
+      { title: "组织编码", key: "" },
+    ],
+  },
+];
+export const initTabColumns = () => tabColumns;
+
+// 初始化公用组件
+import {
+  User,
+  Organization,
+  Department,
+  Supplier,
+  Tax,
+  Currency,
+} from "../../../common-dialog";
+
+export const initComponents = () => ({
+  User,
+  Organization,
+  Department,
+  Supplier,
+  Tax,
+  Currency,
+});

+ 12 - 0
src/views/purchase/purchase-contract/hooks.js

@@ -0,0 +1,12 @@
+export const arr2obj = (data, keyName, valueName) =>
+  Object.fromEntries(data.map((item) => [item[keyName], item[valueName]]));
+
+export const hump2Underline = (str) =>
+  str.replace(/([A-Z])/g, "_$1").toLowerCase();
+
+export const underline2Hump = (str) => {
+  for (let match of str.match(/_(.)/g)) {
+    str = str.replace(match, match.replace("_", "")).toUpperCase();
+  }
+  return str;
+};

+ 2 - 2
src/views/purchase/purchase-contract/index.vue

@@ -1,5 +1,5 @@
 <script>
-import { taskList } from "@/api/business/purchase/purchase-contract";
+import { list } from "@/api/business/purchase/purchase-contract";
 import AddPurchaseContractDrawer from "./add-purchase-contract.vue";
 import SeePurchaseContractDrawer from "./see-purchase-contract.vue";
 // import DirectSourcingTable from "./direct-sourcing.vue";
@@ -124,7 +124,7 @@ export default {
     async fetchTaskList() {
       this.loading = true;
       try {
-        const { code, msg, rows, total } = await taskList({
+        const { code, msg, rows, total } = await list({
           ...this.page,
           ...this.searchParams,
         });

+ 2 - 2
vue.config.js

@@ -38,14 +38,14 @@ module.exports = {
       [process.env.VUE_APP_BASE_API]: {
         // target: `http://172.16.100.107:8080/drp-admin`, //测试
         // target: `http://test-sy.derom.com/drp-admin`, //测试
-        target: `http://release-sy.derom.com/drp-admin`, //预发
+        // target: `http://release-sy.derom.com/drp-admin`, //预发
         // target: `http://sy.derom.com/drp-admin`, //生产
         // target: `http://172.16.63.202:8000/drp-admin`, // D本地
         // target: `http://172.16.62.241:8000/drp-admin`, //笑寒本地
         // target: `http://172.16.13.152:8000/drp-admin`, //豪哥本地
         // target: `http://172.16.13.47:8000/drp-admin`, //石杨本地
         // target: `http://172.16.13.113:8000/drp-admin`, //DWT本地
-        // target: `http://172.16.13.77:8000/drp-admin`, //DWT本地
+        target: `http://172.16.13.77:8000/drp-admin`, //TQ本地
         changeOrigin: true,
         pathRewrite: {
           ["^" + process.env.VUE_APP_BASE_API]: "",