cz 1 yıl önce
ebeveyn
işleme
77c2d4ce38

+ 5 - 0
src/components/testForm/index.vue

@@ -265,6 +265,11 @@
             :readonly="i.readonly != undefined ? i.readonly : false"
             :rules="getRules(i.prop)"
             :required="getRequired(i.prop)"
+            @change="
+              (val) => {
+                return i.changeFn ? i.changeFn(index, val) : () => {};
+              }
+            "
           >
           </van-field>
           <!-- 单选 -->

+ 13 - 5
src/main.js

@@ -1,15 +1,23 @@
-import { createApp } from 'vue'
+import {
+  createApp
+} from 'vue'
 import App from './App.vue'
 import router from './router'
 import i18n from '@/lang/'
+import {
+  moneyFormat,
+  getDictOne,
+} from '@/utils/util'
 const app = createApp(App)
 app.use(router)
 app.use(i18n).mount('#app')
 
 import {
-    post,
-    get
-  } from '@/utils/axios'
+  post,
+  get
+} from '@/utils/axios'
 app.config.globalProperties.get = get
 app.config.globalProperties.post = post
-export default app
+app.config.globalProperties.moneyFormat = moneyFormat
+app.config.globalProperties.getDictOne = getDictOne
+export default app

+ 7 - 4
src/router/index.js

@@ -7,6 +7,9 @@ import main from '../views/main.vue'
 import {
 	routesLXF
 } from './routerLXF.js'
+import {
+	jxskRouter
+} from './jxskRouter.js'
 
 const routes = [{
 		path: '/',
@@ -53,7 +56,7 @@ const routes = [{
 				name: '我的反馈提交',
 				component: () => import('../views/home/feedbackSubmit.vue')
 			},
-			
+
 			{
 				path: 'feedbackDtl',
 				name: '我的反馈详情',
@@ -69,7 +72,7 @@ const routes = [{
 				name: '消息列表',
 				component: () => import('../views/message/messageList.vue')
 			},
-			
+
 			{
 				path: 'iframWinfaster',
 				name: '官网',
@@ -386,12 +389,12 @@ const routes = [{
 				component: () => import('../views/email/write.vue')
 			},
 
-			
+
 		]
 	},
 ]
 
-routes[2].children = routes[2].children.concat(routesLXF())
+routes[2].children = routes[2].children.concat(routesLXF()).concat(jxskRouter())
 
 const router = createRouter({
 	history: createWebHashHistory(),

+ 20 - 0
src/router/jxskRouter.js

@@ -0,0 +1,20 @@
+export function jxskRouter() {
+  const jxskRouter = [{
+    path: "jxskSalesContract",
+    name: "jxsk_销售合同",
+    component: () => import("../views/JXSK/salesContract/index.vue"),
+  }, {
+    path: "jxskSalesContractAdd",
+    name: "jxsk_销售合同添加",
+    component: () => import("../views/JXSK/salesContract/add.vue"),
+  }, {
+    path: "jxskTask",
+    name: "jxsk_生产任务",
+    component: () => import("../views/JXSK/mes/task/index.vue"),
+  }, {
+    path: "jxskTaskAdd",
+    name: "jxsk_生产任务添加",
+    component: () => import("../views/JXSK/mes/task/add.vue"),
+  }];
+  return jxskRouter;
+}

+ 59 - 0
src/utils/util.js

@@ -0,0 +1,59 @@
+import {
+  post,
+  get
+} from '@/utils/axios'
+export function getDictOne(key) {
+  return new Promise((resolve, reject) => {
+    let dictObj = {};
+    let arr = {};
+    let num = 0;
+    for (let i = 0; i < key.length; i++) {
+      const element = key[i];
+      if (dictObj[element]) {
+        arr[element] = dictObj[element];
+        num++;
+        if (num === key.length) {
+          resolve(arr);
+        }
+      } else {
+        post("/tenantDict/getDict", {
+          dictCode: element,
+        }).then((res) => {
+          dictObj[element] = res;
+          arr[element] = res;
+          num++;
+          if (num === key.length) {
+            resolve(arr);
+          }
+        });
+      }
+    }
+  });
+}
+
+// 金额千分符
+export function moneyFormat(s, n) {
+  if (s) {
+    s = s + "";
+    let str = s.slice(0, 1);
+    if (str === "-") {
+      s = s.slice(1, s.length);
+    }
+    n = n > 0 && n <= 20 ? n : 2;
+    s = parseFloat((s + "").replace(/[^\d\.-]/g, "")).toFixed(n) + "";
+    var l = s.split(".")[0].split("").reverse(),
+      r = s.split(".")[1];
+    var t = "";
+    for (let i = 0; i < l.length; i++) {
+      t += l[i] + ((i + 1) % 3 == 0 && i + 1 != l.length ? "," : "");
+    }
+    let result = t.split("").reverse().join("") + "." + r;
+    if (str === "-") {
+      return "-" + result;
+    } else {
+      return result;
+    }
+  } else {
+    return "0.00";
+  }
+}

+ 178 - 0
src/views/JXSK/mes/task/add.vue

@@ -0,0 +1,178 @@
+<template>
+  <div class="form" style="padding-bottom: 60px">
+    <van-nav-bar
+      title="生产任务"
+      left-text="返回"
+      left-arrow
+      @click-left="onClickLeft"
+    >
+    </van-nav-bar>
+    <testForm
+      v-model="formData.data"
+      :formOption="formOption"
+      :formConfig="formConfig"
+      :rules="rules"
+      @onSubmit="onSubmit"
+      ref="formDom"
+    ></testForm>
+  </div>
+</template>
+
+<script setup>
+import { ref, reactive, getCurrentInstance, onMounted } from "vue";
+import { showSuccessToast, showFailToast } from "vant";
+import { useRoute } from "vue-router";
+import testForm from "@/components/testForm/index.vue";
+const proxy = getCurrentInstance().proxy;
+const route = useRoute();
+const formDom = ref(null);
+const formData = reactive({
+  data: {
+    list: [],
+  },
+});
+const rules = {
+  warehouseName: [{ required: true, message: "仓库名称不能为空" }],
+  productName: [{ required: true, message: "物品名称不能为空" }],
+  quantity: [{ required: true, message: "入库数量不能为空" }],
+};
+const formOption = reactive({
+  readonly: false, //用于控制整个表单是否只读
+  disabled: false,
+  labelAlign: "top",
+  scroll: true,
+  labelWidth: "62pk",
+  btnConfig: {
+    isNeed: false,
+    prop: "list",
+    plain: true,
+    listTitle: "",
+    listConfig: [],
+    clickFn: () => {},
+  },
+});
+const formConfig = reactive([
+  {
+    type: "picker",
+    label: "生产计划",
+    prop: "warehouseId",
+    itemType: "onePicker",
+    showPicker: false,
+    fieldNames: {
+      text: "label",
+      value: "value",
+    },
+    data: [],
+  },
+  {
+    type: "input",
+    itemType: "text",
+    label: "产品名称",
+    prop: "reamlke",
+    readonly: true,
+  },
+  {
+    type: "input",
+    itemType: "number",
+    label: "待排程数量",
+    prop: "reamlke",
+    readonly: true,
+  },
+  {
+    type: "input",
+    itemType: "number",
+    label: "任务数量",
+    prop: "reamlke",
+  },
+  {
+    type: "picker",
+    label: "负责人",
+    prop: "warehouseId",
+    itemType: "onePicker",
+    showPicker: false,
+    fieldNames: {
+      text: "label",
+      value: "value",
+    },
+    data: [],
+  },
+  {
+    type: "picker",
+    label: "完成期限",
+    prop: "date",
+    itemType: "datePicker",
+    showPicker: false,
+    split: "-",
+    columnsType: ["year", "month", "day"],
+  },
+]);
+const getDict = () => {
+  proxy
+    .post("/productionPlan/page", { pageNum: 1, pageSize: 9999 })
+    .then((res) => {
+      formConfig[0].data = res.data.rows.map((item) => {
+        return {
+          ...item,
+          label: item.productName,
+          value: item.id,
+        };
+      });
+    });
+
+  proxy.get("/system/user/list?pageNum=1&pageSize=9999").then((res) => {
+    formConfig[4].data = res.rows.map((item) => {
+      return {
+        label: item.userName,
+        value: item.userId,
+      };
+    });
+  });
+};
+
+const onClickLeft = () => history.back();
+const onSubmit = () => {
+  proxy.post("/productionTask/add", formData.data).then(
+    (res) => {
+      setTimeout(() => {
+        showSuccessToast("添加成功");
+        proxy.$router.push("/main/task");
+      }, 500);
+    },
+    (err) => {
+      return showFailToast(err.message);
+    }
+  );
+};
+const getDetails = () => {
+  proxy.post("/productionTask/detail", { id: route.query.id }).then(
+    (res) => {
+      console.log(res, "ada");
+    },
+    (err) => {
+      return showFailToast(err.message);
+    }
+  );
+};
+onMounted(() => {
+  getDict();
+  if (route.query.id) {
+    getDetails();
+  }
+});
+</script>
+<style lang="scss" scoped>
+.row {
+  display: flex;
+  padding: 5px 10px 0 10px;
+  justify-content: space-between;
+  align-items: center;
+  .title {
+    flex: 1;
+  }
+  .delete {
+    width: 20px;
+    cursor: pointer;
+    text-align: center;
+  }
+}
+</style>

+ 126 - 0
src/views/JXSK/mes/task/index.vue

@@ -0,0 +1,126 @@
+<template>
+  <div style="padding-bottom: 60px">
+    <van-nav-bar
+      title="生产任务"
+      left-text=""
+      left-arrow
+      @click-left="onClickLeft"
+      @click-right="onClickRight"
+    >
+      <template #right> 添加 </template>
+    </van-nav-bar>
+    <van-search
+      v-model="req.keyword"
+      placeholder="请输入搜索关键词"
+      @search="onRefresh"
+    />
+
+    <van-pull-refresh v-model="loading" @refresh="onRefresh">
+      <div class="list">
+        <van-list
+          v-model:loading="loading"
+          :finished="finished"
+          finished-text="没有更多了"
+          @load="onLoad"
+          style="margin-bottom: 60px"
+        >
+          <commonList
+            :data="listData"
+            :config="listConfig"
+            :showMore="true"
+            @onClick="toDtl"
+          ></commonList>
+        </van-list>
+      </div>
+    </van-pull-refresh>
+  </div>
+</template>
+<script setup>
+import { ref, getCurrentInstance, onMounted } from "vue";
+import commonList from "@/components/common-list.vue";
+import { useRoute } from "vue-router";
+const loading = ref(false);
+const router = useRoute();
+const req = ref({
+  pageNum: 1,
+  keyword: null,
+});
+const finished = ref(false);
+const proxy = getCurrentInstance().proxy;
+const listData = ref([]);
+
+const listConfig = ref([
+  {
+    label: "任务编码",
+    prop: "code",
+  },
+  {
+    label: "产品名称",
+    prop: "productName",
+  },
+
+  {
+    label: "任务数量",
+    prop: "quantity",
+  },
+  {
+    label: "完成期限",
+    prop: "dueDate",
+  },
+  {
+    label: "负责人",
+    prop: "personLiableName",
+  },
+]);
+const onRefresh = () => {
+  req.value.pageNum = 1;
+  finished.value = false;
+  getList("refresh");
+};
+const onLoad = () => {
+  getList();
+};
+
+const onClickLeft = () => proxy.$router.push("/main/working");
+
+const onClickRight = () => {
+  proxy.$router.push("/main/jxskTaskAdd");
+};
+
+const toDtl = (row) => {
+  proxy.$router.push({
+    path: "/main/jxskTaskAdd",
+    query: {
+      id: row.id,
+    },
+  });
+};
+
+const getList = (type) => {
+  loading.value = true;
+  proxy
+    .post("/productionTask/page", req.value)
+    .then((res) => {
+      listData.value =
+        type === "refresh"
+          ? res.data.rows
+          : listData.value.concat(res.data.rows);
+      if (req.value.pageNum * 10 >= res.data.total) {
+        finished.value = true;
+      }
+      req.value.pageNum++;
+      loading.value = false;
+    })
+    .catch((err) => {
+      loading.value = false;
+    });
+};
+
+getList();
+</script>
+
+<style lang="scss" scoped>
+.list {
+  min-height: 70vh;
+}
+</style>

+ 278 - 0
src/views/JXSK/salesContract/add.vue

@@ -0,0 +1,278 @@
+<template>
+  <div class="form">
+    <van-nav-bar
+      title="销售合同"
+      left-text="返回"
+      left-arrow
+      @click-left="onClickLeft"
+    >
+    </van-nav-bar>
+    <testForm
+      v-model="formData.data"
+      :formOption="formOption"
+      :formConfig="formConfig"
+      :rules="rules"
+      @onSubmit="onSubmit"
+      ref="formDom"
+    ></testForm>
+  </div>
+</template>
+
+<script setup>
+import { ref, reactive, getCurrentInstance, onMounted } from "vue";
+import { showSuccessToast, showFailToast } from "vant";
+import { useRoute } from "vue-router";
+import testForm from "@/components/testForm/index.vue";
+const proxy = getCurrentInstance().proxy;
+const route = useRoute();
+const formDom = ref(null);
+const formData = reactive({
+  data: {
+    list: [],
+  },
+});
+const rules = {
+  warehouseName: [{ required: true, message: "仓库名称不能为空" }],
+  productName: [{ required: true, message: "物品名称不能为空" }],
+  quantity: [{ required: true, message: "入库数量不能为空" }],
+};
+const formOption = reactive({
+  readonly: false, //用于控制整个表单是否只读
+  disabled: false,
+  labelAlign: "top",
+  scroll: true,
+  labelWidth: "62pk",
+  btnConfig: {
+    isNeed: true,
+    prop: "list",
+    plain: true,
+    listTitle: "合同明细",
+    listConfig: [
+      {
+        type: "picker",
+        label: "产品名称",
+        prop: "productId",
+        itemType: "onePicker",
+        showPicker: false,
+        readonly: false,
+        fieldNames: {
+          text: "label",
+          value: "value",
+        },
+        data: [],
+      },
+      {
+        type: "picker",
+        label: "是否定制",
+        prop: "productId",
+        itemType: "onePicker",
+        showPicker: false,
+        readonly: false,
+        fieldNames: {
+          text: "label",
+          value: "value",
+        },
+        data: [
+          {
+            label: "是",
+            value: "1",
+          },
+          {
+            label: "否",
+            value: "2",
+          },
+        ],
+      },
+      {
+        type: "input",
+        itemType: "number",
+        label: "单价",
+        prop: "quantity",
+        clearable: true,
+        changeFn: (index, val) => {
+          changeAmount(index);
+        },
+      },
+      {
+        type: "input",
+        itemType: "number",
+        label: "数量",
+        prop: "quantity1",
+        clearable: true,
+        changeFn: (index, val) => {
+          changeAmount(index);
+        },
+      },
+      {
+        type: "input",
+        itemType: "number",
+        label: "金额小计",
+        prop: "quantity2",
+        placeholder: "根据单价、数量自动计算",
+        readonly: true,
+      },
+    ],
+    clickFn: () => {
+      if (formData.data.list && formData.data.list.length > 0) {
+        formData.data.list.push({
+          productId: "",
+          quantity: "",
+        });
+      } else {
+        formData.data.list = [
+          {
+            productId: "",
+            quantity: "",
+          },
+        ];
+      }
+    },
+  },
+});
+const formConfig = reactive([
+  {
+    type: "picker",
+    label: "客户名称",
+    prop: "warehouseId",
+    itemType: "onePicker",
+    showPicker: false,
+    fieldNames: {
+      text: "label",
+      value: "value",
+    },
+    data: [],
+  },
+  {
+    type: "picker",
+    label: "交货期限",
+    prop: "date",
+    itemType: "datePicker",
+    showPicker: false,
+    split: "-",
+    columnsType: ["year", "month", "day"],
+  },
+  {
+    type: "picker",
+    label: "付款方式",
+    prop: "warehouseId",
+    itemType: "onePicker",
+    showPicker: false,
+    fieldNames: {
+      text: "label",
+      value: "value",
+    },
+    data: [],
+  },
+  {
+    type: "picker",
+    label: "云费支付方",
+    prop: "warehouseId",
+    itemType: "onePicker",
+    showPicker: false,
+    fieldNames: {
+      text: "label",
+      value: "value",
+    },
+    data: [
+      {
+        label: "甲方",
+        value: "1",
+      },
+      {
+        label: "乙方",
+        value: "2",
+      },
+    ],
+  },
+  {
+    type: "input",
+    itemType: "textarea",
+    label: "备注",
+    prop: "reamlke",
+  },
+  {
+    type: "input",
+    itemType: "number",
+    label: "合同总金额",
+    prop: "total",
+    readonly: true,
+  },
+]);
+const onClickLeft = () => history.back();
+const fundsPaymentMethod = ref([]);
+const customerData = ref([]);
+const productData = ref([]);
+const getDict = () => {
+  proxy.getDictOne(["funds_payment_method"]).then((res) => {
+    fundsPaymentMethod.value = res["funds_payment_method"].data.map((x) => ({
+      label: x.dictValue,
+      value: x.dictKey,
+    }));
+    formConfig[2].data = fundsPaymentMethod.value;
+  });
+  proxy.post("/customer/page", { pageNum: 1, pageSize: 9999 }).then((res) => {
+    customerData.value = res.data.rows.map((x) => ({
+      label: x.name,
+      value: x.id,
+    }));
+    formConfig[0].data = customerData.value;
+  });
+  proxy
+    .post("/productInfo/page", { pageNum: 1, pageSize: 9999, definition: "1" })
+    .then((res) => {
+      productData.value = res.data.rows.map((x) => ({
+        label: x.name,
+        value: x.id,
+      }));
+      formOption.btnConfig.listConfig[0].data = productData.value;
+    });
+};
+
+const getDetails = (id) => {
+  proxy.post("/stockJournal/detail", { id }).then((res) => {
+    formData.data = res.data;
+  });
+};
+
+onMounted(() => {
+  getDict();
+  if (route.query.id) getDetails(route.query.id);
+});
+
+const onSubmit = () => {
+  if (!formData.data.list.length > 0) return showFailToast("请添加合同明细!");
+  proxy.post("/stock/add", formData.data).then(
+    () => {
+      showSuccessToast("操作成功");
+      setTimeout(() => {
+        onClickLeft();
+        // proxy.$router.push("/main/manualInbound");
+      }, 500);
+    },
+    (err) => {
+      return showFailToast(err.message);
+    }
+  );
+};
+
+const changeAmount = (index) => {
+  let total = 0;
+  for (let i = 0; i < formData.data.list.length; i++) {
+    const element = formData.data.list[i];
+    if (element.quantity && element.quantity1) {
+      element.quantity2 = parseFloat(
+        element.quantity * element.quantity1
+      ).toFixed(2);
+      total += Number(element.quantity2);
+    }
+  }
+  if (total) {
+    formData.data.total = total.toFixed(2);
+  }
+};
+</script>
+<style lang="scss" scoped>
+.form {
+  margin-bottom: 60px;
+}
+</style>

+ 149 - 0
src/views/JXSK/salesContract/index.vue

@@ -0,0 +1,149 @@
+<template>
+  <van-nav-bar
+    title="销售合同"
+    left-text=""
+    left-arrow
+    @click-left="onClickLeft"
+    @click-right="onClickRight"
+  >
+    <template #right> 添加 </template>
+  </van-nav-bar>
+  <van-search
+    v-model="req.keyword"
+    placeholder="请输入搜索关键词"
+    @search="onRefresh"
+  />
+  <van-pull-refresh v-model="loading" @refresh="onRefresh">
+    <div class="list">
+      <van-list
+        v-model:loading="loading"
+        :finished="finished"
+        finished-text="没有更多了"
+        @load="onLoad"
+        style="margin-bottom: 60px"
+      >
+        <commonList
+          :data="listData"
+          @onClick="toDtl"
+          :config="listConfig"
+        ></commonList>
+      </van-list>
+    </div>
+  </van-pull-refresh>
+</template>
+<script setup>
+import { ref, getCurrentInstance } from "vue";
+import commonList from "@/components/common-list.vue";
+import { useRoute } from "vue-router";
+
+const loading = ref(false);
+const router = useRoute();
+const req = ref({
+  pageNum: 1,
+  keyword: null,
+  definition: "1",
+});
+const finished = ref(false);
+const proxy = getCurrentInstance().proxy;
+const listData = ref([]);
+const classification = ref([]);
+const listConfig = ref([
+  {
+    label: "客户名称",
+    prop: "productClassifyName",
+  },
+  {
+    label: "合同金额",
+    prop: "code",
+  },
+  {
+    label: "签订时间",
+    prop: "name",
+  },
+]);
+const onRefresh = () => {
+  req.value.pageNum = 1;
+  finished.value = false;
+  getList("refresh");
+};
+const onLoad = () => {
+  getClassification();
+};
+const onClickLeft = () => proxy.$router.push("/main/working");
+const onClickRight = () => {
+  proxy.$router.push({
+    path: "jxskSalesContractAdd",
+    query: {
+      type: "add",
+    },
+  });
+};
+const toDtl = (row) => {
+  // proxy.$router.push({
+  //   path: "productLibraryAdd",
+  //   query: {
+  //     id: row.id,
+  //     type: "edit",
+  //   },
+  // });
+};
+const treeToList = (arr) => {
+  let res = []; // 用于存储递归结果(扁平数据)
+  // 递归函数
+  let fn = (source) => {
+    source.forEach((el) => {
+      res.push(el);
+      el.children && el.children.length > 0 ? fn(el.children) : ""; // 子级递归
+    });
+  };
+  fn(arr);
+  return res;
+};
+const getClassification = () => {
+  if (classification.value && classification.value.length > 0) {
+    getList();
+  } else {
+    proxy
+      .post("/productClassify/tree", {
+        parentId: "",
+        name: "",
+        definition: "1",
+      })
+      .then((res) => {
+        classification.value = treeToList(res.data);
+        getList();
+      });
+  }
+};
+const getList = (type) => {
+  loading.value = true;
+  proxy
+    .post("/productInfo/page", req.value)
+    .then((res) => {
+      res.data.rows = res.data.rows.map((item) => {
+        return {
+          ...item,
+          productClassifyName: item.classifyNameGroup.join(" / "),
+        };
+      });
+      listData.value =
+        type === "refresh"
+          ? res.data.rows
+          : listData.value.concat(res.data.rows);
+      if (req.value.pageNum * 10 >= res.data.total) {
+        finished.value = true;
+      }
+      req.value.pageNum++;
+      loading.value = false;
+    })
+    .catch((err) => {
+      loading.value = false;
+    });
+};
+</script>
+
+<style lang="scss" scoped>
+.list {
+  min-height: 70vh;
+}
+</style>