snow 8 months ago
parent
commit
9c1cf3b47f

+ 24 - 0
src/api/serviceParam/grossProfit/index.ts

@@ -0,0 +1,24 @@
+import { http } from "/@/utils/http";
+import { loadEnv } from "@build/index";
+const { VITE_PROXY_DOMAIN_REAL, VITE_PROXY_USER_REAL } = loadEnv();
+const userAPi = VITE_PROXY_DOMAIN_REAL;
+const yewuApi = VITE_PROXY_USER_REAL + "/admin/";
+interface ResponseType extends Promise<any> {
+  data?: object;
+  code?: number;
+  message?: string;
+}
+
+export const httpList = (data:object = {}): ResponseType => {
+  return http.request("post", `${yewuApi}scpList`, { data });
+};
+export const httpStatus = (data:object = {}): ResponseType => {
+  return http.request("post", `${yewuApi}scpStatus`, { data });
+};
+export const httpCreate = (data:object = {}): ResponseType => {
+  return http.request("post", `${yewuApi}excluadd`, { data });
+};
+export const httpUpdate = (data:object = {}): ResponseType => {
+  return http.request("post", `${yewuApi}scpSet`, { data });
+}
+

+ 13 - 0
src/api/serviceParam/purchaseSetting/index.ts

@@ -0,0 +1,13 @@
+import { http } from "/@/utils/http";
+import { loadEnv } from "@build/index";
+const { VITE_PROXY_DOMAIN_REAL, VITE_PROXY_USER_REAL } = loadEnv();
+const userAPi = VITE_PROXY_DOMAIN_REAL;
+const yewuApi = VITE_PROXY_USER_REAL + "/admin/";
+
+export const httpList = (data: object): any => {
+  return http.request("post", `${yewuApi}companyCgd/list`, { data });
+};
+
+export const httpStatus = (data: object): any => {
+  return http.request("post", `${yewuApi}companyCgd/update`, { data });
+};

+ 59 - 0
src/views/serviceParam/grossProfit/_options.ts

@@ -7,3 +7,62 @@ export const khOptions =  [
   { value: '0', label: "组织" },
   { value: '1', label: "企业" },
 ]
+
+const validate_rate = (rule, value, callback) => {
+  const { required } = rule
+  if ((value === '' || value === undefined) && required) {
+    callback(new Error('主管利率毛利率不能为空!'))
+  } else {
+    callback()
+  }
+}
+const validate_order_rate = (rule, value, callback) => {
+  const { required } = rule
+  if ((value === '' || value === undefined) && required) {
+    callback(new Error('预算→成本毛利率不能为空!'))
+  } else {
+    callback()
+  }
+}
+const validate_sale_rate = (rule, value, callback) => {
+  const { required } = rule
+  if ((value === '' || value === undefined) && required) {
+    callback(new Error('成本→售价毛利率不能为空!'))
+  } else {
+    callback()
+  }
+}
+
+const validate_lower_rate = (rule, value, callback) => {
+  const { required } = rule
+  if ((value === '' || value === undefined) && required) {
+    callback(new Error('BOSS毛利率不能为空!'))
+  } else {
+    callback()
+  }
+}
+const validate_low_rate = (rule, value, callback) => {
+  const { required } = rule
+  if ((value === '' || value === undefined) && required) {
+    callback(new Error('项目最低毛利率不能为空!'))
+  } else {
+    callback()
+  }
+}
+const validate_money_rate = (rule, value, callback) => {
+  const { required } = rule
+  if ((value === '' || value === undefined) && required) {
+    callback(new Error('财务毛利率不能为空!'))
+  } else {
+    callback()
+  }
+}
+
+export const rules =  {
+  order_rate: [{ required: true, validator: validate_order_rate, trigger: 'blur' }],
+  sale_rate: [{ required: true, validator: validate_sale_rate, trigger: 'blur' }],
+  lower_rate: [{ required: false, validator: validate_lower_rate, trigger: 'blur' }],
+  rate: [{ required: true, validator: validate_rate, trigger: 'blur' }],
+  low_rate: [{ required: true, validator: validate_low_rate, trigger: 'blur' }],
+  money_rate: [{ required: true, validator: validate_money_rate, trigger: 'blur' }]
+}

+ 12 - 12
src/views/serviceParam/grossProfit/cpns/category-tree.vue

@@ -1,19 +1,19 @@
 <script setup lang="ts">
 import { ref, shallowRef,  watch } from "vue";
 import { useAsync, useResponseHandle } from "/@/hooks/core/useAsync";
-import { httpList, httpDelete, httpStatus } from "/@/api/serviceParam/business";
+import { httpList, httpStatus } from "/@/api/serviceParam/grossProfit";
 import { useRenderIcon } from "/@/components/ReIcon/src/hooks";
 import { statusOptions, khOptions } from "../_options";
 import { ElMessageBox, ElMessage } from "element-plus"
-import { useCompany } from "/@/hooks/core/useCompany";
 import Modal from "./modal.vue"
+import { useCompany } from "/@/hooks/core/useCompany";
+const { currentCompany } = useCompany()
 
 
 const emit = defineEmits(["breadcrumbChange"]);
 const props = defineProps<{ otherParms: Record<string, string>; breadcrumb: any[] }>();
 
 
-const { currentCompany } = useCompany()
 
 const pid = ref("")
 const dataSource = ref<any>({})
@@ -38,6 +38,7 @@ function requestCategorylist() {
   const params = { 
     ...props.otherParms, 
     ...(pid.value ? { pid: pid.value } : { pid : 0 }), 
+    size: 1000,
     companyNo: currentCompany.value.companyNo 
   }
 
@@ -61,15 +62,17 @@ function onDelete(id: string) {
 
 
 function onEdit(row: any = {}) {
-  const { id, cat_name, order_rate , sale_rate , rate , low_rate } = row;
-  dataSource.value = { id, cat_name , order_rate : order_rate || 0, sale_rate : sale_rate || 0, rate : rate || 0, low_rate: low_rate || 0 }
+  console.log(row)
+
+  const { cat_id, cat_name, order_rate , sale_rate , rate , low_rate } = row;
+  dataSource.value = { id: cat_id, cat_name , order_rate : order_rate || 0, sale_rate : sale_rate || 0, rate : rate || 0, low_rate: low_rate || 0 }
   visible.value = true
 }
 
 
 const handleStatus = async row => {
-  const { id, status } = row;
-  const { code, message } = await httpStatus({ status: status + "" === "1" ? "0" : "1", id })
+  const { cat_id, status, companyNo } = row;
+  const { code, message } = await httpStatus({ companyNo: currentCompany.value.companyNo, status: status + "" === "1" ? "0" : "1", cat_id })
 
   responseHandle({
     code,
@@ -86,7 +89,7 @@ defineExpose({ changePid: (id: string) => (pid.value = id), onSearch: () => requ
 
 <template>
   <ul class="mt-[10px]" v-loading="loading">
-    <ElTable :data="data" border size="small">
+    <ElTable :data="data" border size="small" max-height="calc(100vh - 160px)">
       <ElTableColumn label="分类名称" prop="cat_name" min-width="160px" show-overflow-tooltip />
       <ElTableColumn label="状态" prop="status" min-width="70px">
         <template #="{ row }">
@@ -101,10 +104,7 @@ defineExpose({ changePid: (id: string) => (pid.value = id), onSearch: () => requ
           <el-tooltip effect="dark" content="编辑专属分类" placement="top">
             <ElButton link class="reset-margin" type="primary" :icon="useRenderIcon('edits')" @click="onEdit(row)" />
           </el-tooltip>
-          <el-tooltip effect="dark" content="删除专属分类" placement="top">
-            <ElButton link class="reset-margin" type="primary" :icon="useRenderIcon('delete')"
-              @click="onDelete(row.id)" />
-          </el-tooltip>
+
           <el-popconfirm :title=" String(row.status) === '1' ? '改为禁用?' : '改为启用?'" @confirm="handleStatus(row)"  >
               <template #reference>
                 <el-button

+ 26 - 23
src/views/serviceParam/grossProfit/cpns/modal.vue

@@ -1,26 +1,30 @@
 <script setup lang="ts">
-import { httpCreate, httpUpdate } from "/@/api/serviceParam/exclusive";
+import { httpUpdate } from "/@/api/serviceParam/grossProfit";
 import { computed, ref, shallowRef } from "vue";
 import { useVModel } from "@vueuse/core"
-
 import { ElMessage, ElForm } from "element-plus";
+import { rules } from "./../_options"
+
+import { useCompany } from "/@/hooks/core/useCompany";
+const { currentCompany } = useCompany()
 
 const initialData = { pid: '', name: '', id: '' , companyNo: ''}
 const emit = defineEmits(['refresh'])
 
 
-const props = withDefaults(defineProps<{ data: any; pid: string; visible: boolean, breadcrumb: any[] }>(), { data: {  companyNo: '',name: '', pid: '', id: '' } })
+const props = withDefaults(
+  defineProps<{ data: any; pid: string; visible: boolean, breadcrumb: any[] }>(), 
+  { data: {  } }
+)
 
 const data = useVModel(props, 'data')
 const visible = useVModel(props, 'visible')
-const title = computed(() => data.value.id ? '编辑专属类型' : '添加专属类型')
+const title = computed(() => data.value.id ? '编辑业务公司分类毛利' : '添加业务公司分类毛利')
 const prefix = computed(() => { const { breadcrumb = [] } = props; return breadcrumb.slice(0).map(({ name }) => name).join('/') })
 
 const loading = shallowRef(false)
 const formRef = ref<any | null>(null)
 
-const rules = { name: [{ required: true, trigger: 'blur', message:'请输入专属类型名称'}] }
-
 function handleClose(){
   data.value = { ...initialData }
   visible.value = false
@@ -29,24 +33,23 @@ function handleClose(){
 async function onSubmit(){
   try {
     await formRef.value.validate();
-    const { id } = props.data
-    const parameter = { pid: props.pid || '0', name: data.value.name }
-    const isCreate = id === undefined || !id
-    if(!isCreate) parameter.id = id
-
     loading.value = true
-    const api = isCreate ? httpCreate : httpUpdate
-    const res = await api(parameter)
-    loading.value = false
+    
+    const res = await httpUpdate({
+      money_rate: 0,
+      ...data.value,
+      cat_id: data.value.id,
+      companyNo: currentCompany.value.companyNo
+    })
 
+    loading.value = false
     if (res.code === 0) {
       visible.value = false
-      ElMessage.success(`${isCreate ? '添加' : '更新'}成功`)
+      ElMessage.success(`更新成功`)
       emit('refresh')
     } else {
-      ElMessage.warning(`${isCreate ? '添加' : '更新'}失败`)
+      ElMessage.warning(`更新失败`)
     }
-
   } catch (err) {
     console.log(err);
   }
@@ -57,34 +60,34 @@ async function onSubmit(){
 <template>
   <ElDialog v-model="visible" :title="title" center @close="handleClose">
     <ElForm :model="data" :rules="rules" size="small" ref="formRef" label-width="100px">
-      <ElFormItem label="分类名称" prop="cat_name">
-        <ElInput v-model="data.cat_name" disbaled />
+      <ElFormItem label="分类名称" prop="cat_name" >
+        <ElInput v-model="data.cat_name" placeholder="分类名称" :disabled="data.id" />
       </ElFormItem>
 
       <ElFormItem  label="预算→成本" prop="order_rate">
         <div class="flex w-full">
-          <ElInputNumber style="width:100%" :min="0" :max="100" controls-position="right" v-model="data.order_rate" disbaled  precision="2" />
+          <ElInputNumber placeholder="预算→成本" style="width:100%" :min="0" :max="100" controls-position="right" v-model="data.order_rate" disbaled  precision="2" />
           <p class="ml-[10px]">%</p>
         </div>
       </ElFormItem>
       
       <ElFormItem  label="成本→售价" prop="sale_rate">
         <div class="flex w-full">
-          <ElInputNumber style="width:100%"  :min="0" :max="100" controls-position="right" v-model="data.sale_rate" disbaled  precision="2" />
+          <ElInputNumber  placeholder="成本→售价" style="width:100%"  :min="0" :max="100" controls-position="right" v-model="data.sale_rate" disbaled  precision="2" />
           <p class="ml-[10px]">%</p>
         </div>
       </ElFormItem>
 
       <ElFormItem  label="主管利率" prop="rate">
         <div class="flex w-full">
-          <ElInputNumber style="width:100%"  :min="0" :max="100" controls-position="right" v-model="data.rate" disbaled  precision="2" />
+          <ElInputNumber placeholder="主管利率" style="width:100%"  :min="0" :max="100" controls-position="right" v-model="data.rate" disbaled  precision="2" />
           <p class="ml-[10px]">%</p>
         </div>
       </ElFormItem>
 
       <ElFormItem  label="项目最低毛利" prop="low_rate">
         <div class="flex w-full">
-          <ElInputNumber style="width:100%"  :min="0" :max="100" controls-position="right" v-model="data.low_rate" disbaled  precision="2" />
+          <ElInputNumber placeholder="项目最低毛利" style="width:100%"  :min="0" :max="100" controls-position="right" v-model="data.low_rate" disbaled  precision="2" />
           <p class="ml-[10px]">%</p>
         </div>
       </ElFormItem>

+ 2 - 5
src/views/serviceParam/grossProfit/index.vue

@@ -17,7 +17,6 @@ const params = ref<Record<string, string>>({ status: "", cat_name: "", company_n
 const categoryTreeRef = ref<InstanceType<typeof CategoryTree> | null>(null);
 
 function handleChange (depart: any){
-  console.log(depart, '----')
   breadcrumb.value.push(depart)
 }
 
@@ -55,7 +54,7 @@ watch(
 
     <div class="flex justify-between pt-[20px]">
       <div class="flex gap-1">
-        <ElSelect 
+        <!-- <ElSelect 
           v-model="params.status" 
           placeholder="分类状态"
           style="width: 100%" 
@@ -66,8 +65,7 @@ watch(
             :value="opt.value" 
             :label="opt.label" 
           />
-        </ElSelect>
-
+        </ElSelect> -->
         <ElInput 
           @change="() => categoryTreeRef!.onSearch()" 
           v-model="params.cat_name" 
@@ -77,7 +75,6 @@ watch(
         />
       </div>
       <div class="flex">
-        <ElButton size="small" type="primary" @click="visible = true">添加</ElButton>
         <ElButton size="small" @click="() => categoryTreeRef!.onSearch()">刷新</ElButton>
       </div>
     </div>

+ 68 - 0
src/views/serviceParam/platformGrossProfit/_options.ts

@@ -0,0 +1,68 @@
+export const statusOptions = [
+  { value: '0', label: '禁用' },
+  { value: '1', label: '启用' },
+]
+
+export const khOptions =  [
+  { value: '0', label: "组织" },
+  { value: '1', label: "企业" },
+]
+
+const validate_rate = (rule, value, callback) => {
+  const { required } = rule
+  if ((value === '' || value === undefined) && required) {
+    callback(new Error('主管利率毛利率不能为空!'))
+  } else {
+    callback()
+  }
+}
+const validate_order_rate = (rule, value, callback) => {
+  const { required } = rule
+  if ((value === '' || value === undefined) && required) {
+    callback(new Error('预算→成本毛利率不能为空!'))
+  } else {
+    callback()
+  }
+}
+const validate_sale_rate = (rule, value, callback) => {
+  const { required } = rule
+  if ((value === '' || value === undefined) && required) {
+    callback(new Error('成本→售价毛利率不能为空!'))
+  } else {
+    callback()
+  }
+}
+
+const validate_lower_rate = (rule, value, callback) => {
+  const { required } = rule
+  if ((value === '' || value === undefined) && required) {
+    callback(new Error('BOSS毛利率不能为空!'))
+  } else {
+    callback()
+  }
+}
+const validate_low_rate = (rule, value, callback) => {
+  const { required } = rule
+  if ((value === '' || value === undefined) && required) {
+    callback(new Error('项目最低毛利率不能为空!'))
+  } else {
+    callback()
+  }
+}
+const validate_money_rate = (rule, value, callback) => {
+  const { required } = rule
+  if ((value === '' || value === undefined) && required) {
+    callback(new Error('财务毛利率不能为空!'))
+  } else {
+    callback()
+  }
+}
+
+export const rules =  {
+  order_rate: [{ required: true, validator: validate_order_rate, trigger: 'blur' }],
+  sale_rate: [{ required: true, validator: validate_sale_rate, trigger: 'blur' }],
+  lower_rate: [{ required: false, validator: validate_lower_rate, trigger: 'blur' }],
+  rate: [{ required: true, validator: validate_rate, trigger: 'blur' }],
+  low_rate: [{ required: true, validator: validate_low_rate, trigger: 'blur' }],
+  money_rate: [{ required: true, validator: validate_money_rate, trigger: 'blur' }]
+}

+ 133 - 0
src/views/serviceParam/platformGrossProfit/cpns/category-tree.vue

@@ -0,0 +1,133 @@
+<script setup lang="ts">
+import { ref, shallowRef,  watch } from "vue";
+import { useAsync, useResponseHandle } from "/@/hooks/core/useAsync";
+import { httpList, httpStatus } from "/@/api/serviceParam/grossProfit";
+import { useRenderIcon } from "/@/components/ReIcon/src/hooks";
+import { statusOptions, khOptions } from "../_options";
+import { ElMessageBox, ElMessage } from "element-plus"
+import Modal from "./modal.vue"
+import { useCompany } from "/@/hooks/core/useCompany";
+const { currentCompany } = useCompany()
+
+
+const emit = defineEmits(["breadcrumbChange"]);
+const props = defineProps<{ otherParms: Record<string, string>; breadcrumb: any[] }>();
+
+
+
+const pid = ref("")
+const dataSource = ref<any>({})
+const visible = shallowRef(false)
+const responseHandle = useResponseHandle()
+
+const { data, loading, run } = useAsync<any>({ isList: true });
+function toNextNode(depart: any) {
+  pid.value = depart.cat_id;
+  requestCategorylist();
+  emit("breadcrumbChange", depart);
+}
+
+function requestCategorylist() {
+  if(!currentCompany.value.companyNo){
+    ElMessage.warning('请在右上角选择一家业务公司!')
+    loading.value = false
+    data.value = []
+    return
+  }
+
+  const params = { 
+    ...props.otherParms, 
+    ...(pid.value ? { pid: pid.value } : { pid : 0 }), 
+    size: 1000,
+    companyNo: currentCompany.value.companyNo 
+  }
+
+
+  run(httpList(params));
+}
+
+const initialData = () => requestCategorylist()
+function onDelete(id: string) {
+  ElMessageBox.confirm('确认要删除?', { confirmButtonText: "确定", cancelButtonText: "取消", type: "warning" }).then(async () => {
+    const model = { id }
+    const res = await httpDelete(model)
+    if (res.code === 0) {
+      ElMessage.success('删除成功')
+      requestCategorylist()
+    } else {
+      ElMessage.warning('删除失败')
+    }
+  })
+}
+
+
+function onEdit(row: any = {}) {
+  console.log(row)
+
+  const { cat_id, cat_name, order_rate , sale_rate , rate , low_rate } = row;
+  dataSource.value = { id: cat_id, cat_name , order_rate : order_rate || 0, sale_rate : sale_rate || 0, rate : rate || 0, low_rate: low_rate || 0 }
+  visible.value = true
+}
+
+
+const handleStatus = async row => {
+  const { cat_id, status, companyNo } = row;
+  const { code, message } = await httpStatus({ companyNo: currentCompany.value.companyNo, status: status + "" === "1" ? "0" : "1", cat_id })
+
+  responseHandle({
+    code,
+    message,
+    handler: () => requestCategorylist()
+  });
+};
+
+
+initialData();
+watch(() => currentCompany.value, requestCategorylist)
+defineExpose({ changePid: (id: string) => (pid.value = id), onSearch: () => requestCategorylist() });
+</script>
+
+<template>
+  <ul class="mt-[10px]" v-loading="loading">
+    <ElTable :data="data" border size="small" max-height="calc(100vh - 160px)">
+      <ElTableColumn label="分类名称" prop="cat_name" min-width="160px" show-overflow-tooltip />
+      <ElTableColumn label="状态" prop="status" min-width="70px">
+        <template #="{ row }">
+          <ElTag :type="String(row.status) === '0' ? 'warning' : ''">{{ statusOptions.find(({ value }) => value === String(row.status))?.label || '--' }}</ElTag>
+        </template>
+      </ElTableColumn>
+
+      <ElTableColumn label="分类等级" prop="level" min-width="80px" />
+
+      <ElTableColumn label="操作" width="140px">
+        <template #="{ row }">
+          <el-tooltip effect="dark" content="编辑专属分类" placement="top">
+            <ElButton link class="reset-margin" type="primary" :icon="useRenderIcon('edits')" @click="onEdit(row)" />
+          </el-tooltip>
+
+          <el-popconfirm :title=" String(row.status) === '1' ? '改为禁用?' : '改为启用?'" @confirm="handleStatus(row)"  >
+              <template #reference>
+                <el-button
+                  class="reset-margin"
+                  link
+                  type="primary"
+                  size="small"
+                  :icon=" useRenderIcon(String(row.status) === '1' ? 'close-circle-line' : 'checkbox-circle-line')" />
+                </template>
+              </el-popconfirm>
+              <el-tooltip effect="dark" content="下一级" placement="top">
+            <ElButton link class="reset-margin" type="primary" :icon="useRenderIcon('arrow-right-s-line')"  @click="toNextNode(row)" />
+          </el-tooltip>
+        </template>
+      </ElTableColumn>
+    </ElTable>
+
+    <Modal 
+      :pid="pid" 
+      v-model:data="dataSource" 
+      v-model:visible="visible" 
+      :breadcrumb="breadcrumb"  
+      @refresh="requestCategorylist" 
+    />
+  </ul>
+</template>

+ 104 - 0
src/views/serviceParam/platformGrossProfit/cpns/modal.vue

@@ -0,0 +1,104 @@
+<script setup lang="ts">
+import { httpUpdate } from "/@/api/serviceParam/grossProfit";
+import { computed, ref, shallowRef } from "vue";
+import { useVModel } from "@vueuse/core"
+import { ElMessage, ElForm } from "element-plus";
+import { rules } from "./../_options"
+
+import { useCompany } from "/@/hooks/core/useCompany";
+const { currentCompany } = useCompany()
+
+const initialData = { pid: '', name: '', id: '' , companyNo: ''}
+const emit = defineEmits(['refresh'])
+
+
+const props = withDefaults(
+  defineProps<{ data: any; pid: string; visible: boolean, breadcrumb: any[] }>(), 
+  { data: {  } }
+)
+
+const data = useVModel(props, 'data')
+const visible = useVModel(props, 'visible')
+const title = computed(() => data.value.id ? '编辑业务公司分类毛利' : '添加业务公司分类毛利')
+const prefix = computed(() => { const { breadcrumb = [] } = props; return breadcrumb.slice(0).map(({ name }) => name).join('/') })
+
+const loading = shallowRef(false)
+const formRef = ref<any | null>(null)
+
+function handleClose(){
+  data.value = { ...initialData }
+  visible.value = false
+}
+
+async function onSubmit(){
+  try {
+    await formRef.value.validate();
+    loading.value = true
+    
+    const res = await httpUpdate({
+      money_rate: 0,
+      ...data.value,
+      cat_id: data.value.id,
+      companyNo: currentCompany.value.companyNo
+    })
+
+    loading.value = false
+    if (res.code === 0) {
+      visible.value = false
+      ElMessage.success(`更新成功`)
+      emit('refresh')
+    } else {
+      ElMessage.warning(`更新失败`)
+    }
+  } catch (err) {
+    console.log(err);
+  }
+}
+</script>
+
+
+<template>
+  <ElDialog v-model="visible" :title="title" center @close="handleClose">
+    <ElForm :model="data" :rules="rules" size="small" ref="formRef" label-width="100px">
+      <ElFormItem label="分类名称" prop="cat_name" >
+        <ElInput v-model="data.cat_name" placeholder="分类名称" :disabled="data.id" />
+      </ElFormItem>
+
+      <ElFormItem  label="预算→成本" prop="order_rate">
+        <div class="flex w-full">
+          <ElInputNumber placeholder="预算→成本" style="width:100%" :min="0" :max="100" controls-position="right" v-model="data.order_rate" disbaled  precision="2" />
+          <p class="ml-[10px]">%</p>
+        </div>
+      </ElFormItem>
+      
+      <ElFormItem  label="成本→售价" prop="sale_rate">
+        <div class="flex w-full">
+          <ElInputNumber  placeholder="成本→售价" style="width:100%"  :min="0" :max="100" controls-position="right" v-model="data.sale_rate" disbaled  precision="2" />
+          <p class="ml-[10px]">%</p>
+        </div>
+      </ElFormItem>
+
+      <ElFormItem  label="主管利率" prop="rate">
+        <div class="flex w-full">
+          <ElInputNumber placeholder="主管利率" style="width:100%"  :min="0" :max="100" controls-position="right" v-model="data.rate" disbaled  precision="2" />
+          <p class="ml-[10px]">%</p>
+        </div>
+      </ElFormItem>
+
+      <ElFormItem  label="项目最低毛利" prop="low_rate">
+        <div class="flex w-full">
+          <ElInputNumber placeholder="项目最低毛利" style="width:100%"  :min="0" :max="100" controls-position="right" v-model="data.low_rate" disbaled  precision="2" />
+          <p class="ml-[10px]">%</p>
+        </div>
+      </ElFormItem>
+
+      <div class="w-full flex justify-end">
+        <ElButton 
+          type="primary" 
+          :loading="loading" 
+          @click="onSubmit"
+        >保存</ElButton>
+      </div>
+    </ElForm>
+  </ElDialog>
+</template>

+ 101 - 0
src/views/serviceParam/platformGrossProfit/index.vue

@@ -0,0 +1,101 @@
+<script setup lang="ts">
+import { ref, shallowRef, watch } from "vue";
+import { httpCreate } from "/@/api/interest/organize";
+import { statusOptions } from "./_options"
+import { ElMessage, ElOption } from "element-plus"
+import Modal from "./cpns/modal.vue"
+
+import CategoryTree from "./cpns/category-tree.vue"
+
+const pageName = "grossProfit";
+
+const parent = ref(null)
+const data = ref<any>({})
+const breadcrumb = ref<any[]>([]);
+const visible = shallowRef(false)
+const params = ref<Record<string, string>>({ status: "", cat_name: "", company_name: '' });
+const categoryTreeRef = ref<InstanceType<typeof CategoryTree> | null>(null);
+
+function handleChange (depart: any){
+  breadcrumb.value.push(depart)
+}
+
+function handleCategoryTreeSearch(index?: number) {
+  if (index === breadcrumb.value.length - 1) { return }
+  const item = breadcrumb.value[index];
+  const id = item ? item.id : "";
+  categoryTreeRef.value!.changePid(id);
+  categoryTreeRef.value!.onSearch();
+  breadcrumb.value['splice'](index + 1);
+}
+
+watch(
+  () => breadcrumb.value,
+  () => {
+    const business = breadcrumb.value[breadcrumb.value.length - 1]
+    data.value.companyNo = business ? business.companyNo : ''
+    data.value.pid = business ? business.id : '0'
+  },
+  { immediate: true, deep: true }
+)
+</script>
+
+<template>
+  <PageAuth class="px-[10px] h-[calc(100vh-60px)] bg-white" :pageName="pageName" :margin="false">
+    <ul class="flex cursor-pointer">
+      <li @click="() => handleCategoryTreeSearch()">全部专属一级分类 <span v-if="breadcrumb.length > 0" class="mx-[5px]">/</span> </li>
+      <li v-for="(item, index) in breadcrumb" :key="item.id"
+        :class="{ 'cursor-pointer': true, 'text-[#ccc]': index === breadcrumb.length - 1 }"
+        @click="() => handleCategoryTreeSearch(index)">
+        {{ item.cat_name }}
+        <span class="mx-[5px]" v-if="index !== breadcrumb.length - 1">/</span>
+      </li>
+    </ul>
+
+    <div class="flex justify-between pt-[20px]">
+      <div class="flex gap-1">
+        <ElSelect 
+          v-model="params.status" 
+          placeholder="分类状态"
+          style="width: 100%" >
+          <ElOption 
+            v-for="opt in statusOptions" 
+            :key="opt.value" 
+            :value="opt.value" 
+            :label="opt.label" 
+          />
+        </ElSelect>
+
+
+        <ElInput 
+          @change="() => categoryTreeRef!.onSearch()" 
+          v-model="params.cat_name" 
+          placeholder="分类名称" 
+          size="small" 
+          clearable
+        />
+      </div>
+      <div class="flex">
+        <ElButton size="small" @click="() => categoryTreeRef!.onSearch()">刷新</ElButton>
+      </div>
+    </div>
+
+    <!-- 树节点 -->
+    <div class="flex-1">
+      <CategoryTree 
+        ref="categoryTreeRef" 
+        :otherParms="params" 
+        :breadcrumb="breadcrumb"
+        @breadcrumbChange="handleChange" 
+      />
+    </div>
+
+    <Modal 
+      :pid="data.pid" 
+      v-model:data="data" 
+      v-model:visible="visible"
+      :breadcrumb="breadcrumb" 
+      @refresh="categoryTreeRef!.onSearch()" 
+    />
+  </PageAuth>
+</template>

+ 0 - 0
src/views/serviceParam/platformGrossProfit/业务公司分类毛利.md


+ 4 - 0
src/views/serviceParam/purchaseSetting/config/_options.ts

@@ -0,0 +1,4 @@
+export const statusOptions = [
+  { value: "0", label: "禁用" },
+  { value: "1", label: "启用" },
+];

+ 55 - 0
src/views/serviceParam/purchaseSetting/config/content.config.ts

@@ -0,0 +1,55 @@
+import { httpList, httpStatus } from "/@/api/serviceParam/purchaseSetting";
+
+import { h } from "vue";
+import { ContentConfig } from "/@/components/PageContent";
+import { ElTag } from "element-plus";
+
+const columns = [
+  {
+    prop: "companyName",
+    label: "业务公司",
+  },
+  {
+    prop: "is_cgd",
+    label: "状态",
+    cellRenderer: ({ row }) => {
+      return h(
+        ElTag,
+        {
+          type: String(row.is_cgd) === "1" ? "success" : "danger"
+        },
+        {
+          default: () => (String(row.is_cgd) === "1" ? "启用" : "禁用")
+        }
+      );
+    }
+  },
+  {
+    prop: "apply_name",
+    label: "创建人",
+  },
+  {
+    prop: "addtime",
+    label: "创建时间",
+  },
+  {
+    prop: "操作",
+    label: "操作",
+    width: '80px',
+    _slot_: 'operation'
+  }
+];
+
+const contentConfig: ContentConfig = {
+  title: "商品分类查询",
+  columns,
+  apis: {
+    httpStatus,
+    httpList:(params = {} as any) => {
+      const { is_cgd, ...rest } = params
+      return httpList({ is_cgd: is_cgd || '', ...rest })
+    }
+  }
+};
+
+export default contentConfig;

+ 26 - 0
src/views/serviceParam/purchaseSetting/config/search.config.ts

@@ -0,0 +1,26 @@
+import { FormConfig } from "/@/components/PageSearch"
+import { statusOptions } from "./_options";
+
+const searchFormConfig: FormConfig = {
+  formItems: [
+    {
+      field: "create_timer",
+      type: "date_picker",
+      otherOptions: {
+        type: "daterange",
+        startProp: "start",
+        endProp: "end",
+        startPlaceholder: "开始时间",
+        endPlaceholder: "结束时间"
+      }
+    },
+    {
+      field: "is_cgd",
+      type: "select",
+      options: statusOptions,
+      placeholder:'状态'
+    }
+  ]
+};
+
+export default searchFormConfig;

+ 69 - 0
src/views/serviceParam/purchaseSetting/index.vue

@@ -0,0 +1,69 @@
+<script setup lang="ts">
+import { ref } from "vue";
+import contentConfig from "./config/content.config";
+import searchConfig from "./config/search.config";
+import { usePageSearch, type PageHooks, type PageEvents } from "/@/hooks/page";
+import { httpAdd, httpUpdate } from "/@/api/serviceParam/orderuse";
+
+import { ElMessage } from "element-plus"
+
+const PageName = "purchaseSetting";
+const instance = ref<any>(null);
+
+const disabled = ref(false)
+const visible = ref(false)
+const data = ref<any>({})
+
+const hooks: PageHooks = {
+  pageSearchHook: () => usePageSearch(undefined, undefined, searchConfig)
+};
+
+const events: PageEvents = {
+  content: {
+    create: () => {
+      disabled.value = false
+      visible.value = true
+    },
+    preview: _data => {
+      const { id, order_use } = _data
+      data.value = { id, order_use }
+      disabled.value = true
+      visible.value = true
+    },
+    update: _data => {
+      const { id, order_use } = _data
+      data.value = { id, order_use }
+      disabled.value = false
+      visible.value = true
+    }
+  }
+};
+
+async function onSubmit() {
+  const { id, order_use } = data.value;
+  const isCreate = id === undefined || !id
+  const params = { id, order_use }
+  if (isCreate) delete params['id']
+  const api = isCreate ? httpAdd : httpUpdate
+  const result = await api(params)
+  if (result.code === 0) {
+    visible.value = false
+    ElMessage.success(`${isCreate ? '添加' : '更新'}成功`)
+    instance.value!.onSearch()
+  } else {
+    ElMessage.warning(`${isCreate ? '添加' : '更新'}失败`)
+  }
+}
+</script>
+
+<template>
+  <PageAuth :pageName="PageName">
+    <PageContainer 
+      :hooks="hooks" 
+      :events="events" 
+      :contentConfig="contentConfig" 
+      :search-config="searchConfig"
+      :get-content-ref="ref => (instance = ref)"
+    />
+  </PageAuth>
+</template>

+ 0 - 0
src/views/serviceParam/purchaseSetting/采购单修改设置.md