소스 검색

feat: ✨ 完成仓库列表,完成产品分类,以及产品列表

@sun-chaoqun 2 년 전
부모
커밋
e5dffa9f07

+ 1 - 0
.env

@@ -1,5 +1,6 @@
 VITE_BZD_ERP_APP_TITLE = 'ERP宝智达'
 
+# VITE_BZD_ERP_APP_API = 'https://erp.baozhida.cn'
 VITE_BZD_ERP_APP_API = 'https://erp.baozhida.cn'
 
 VITE_BZD_ERPOSS_APP_API = 'https://erposs.baozhida.cn'

+ 4 - 0
README.md

@@ -16,6 +16,10 @@
 
 考勤管理 https://erp.baozhida.cn/api/ams
 
+#### 测试环境
+
+https://erp.baozhida.cn/testapi/storage
+
 ### 原型
 
 https://58ftdz.axshare.com

+ 2 - 0
components.d.ts

@@ -26,6 +26,7 @@ declare module '@vue/runtime-core' {
     ElDescriptions: typeof import('element-plus/es')['ElDescriptions']
     ElDescriptionsItem: typeof import('element-plus/es')['ElDescriptionsItem']
     ElDialog: typeof import('element-plus/es')['ElDialog']
+    ElDivider: typeof import('element-plus/es')['ElDivider']
     ElDrawer: typeof import('element-plus/es')['ElDrawer']
     ElDropdown: typeof import('element-plus/es')['ElDropdown']
     ElDropdownItem: typeof import('element-plus/es')['ElDropdownItem']
@@ -59,5 +60,6 @@ declare module '@vue/runtime-core' {
     RouterLink: typeof import('vue-router')['RouterLink']
     RouterView: typeof import('vue-router')['RouterView']
     TableBase: typeof import('./src/components/TableBase/index.vue')['default']
+    Upload: typeof import('./src/components/Upload/index.vue')['default']
   }
 }

+ 43 - 0
src/api/storehouse/index.ts

@@ -0,0 +1,43 @@
+import $http from '../index'
+
+/**
+ * 仓库
+ */
+// 仓库列表
+export const Storehouse_Depot_List = (params: any) => $http.post('/testapi/storage/Depot/List', params)
+// 仓库添加
+export const Storehouse_Depot_Add = (params: any) => $http.post('/testapi/storage/Depot/Add', params)
+// 仓库修改
+export const Storehouse_Depot_Edit = (params: any) => $http.post('/testapi/storage/Depot/Edit', params)
+// 仓库删除
+export const Storehouse_Depot_Del = (params: any) => $http.post('/testapi/storage/Depot/Del', params)
+
+/**
+ * 产品分类
+ */
+// 产品列表
+export const Storehouse_ProductClass_List = (params: any) => $http.post('/testapi/storage/ProductClass/List', params)
+// 产品添加
+export const Storehouse_ProductClass_Add = (params: any) => $http.post('/testapi/storage/ProductClass/Add', params)
+// 产品修改
+export const Storehouse_ProductClass_Edit = (params: any) => $http.post('/testapi/storage/ProductClass/Edit', params)
+// 产品删除
+export const Storehouse_ProductClass_Del = (params: any) => $http.post('/testapi/storage/ProductClass/Del', params)
+
+/**
+ * 产品
+ */
+// 产品名称
+export const Storehouse_Product_Name_List = (params: any) => $http.post('/testapi/storage/Product/Name_List', params)
+// 产品型号
+export const Storehouse_Product_Model_List = (params: any) => $http.post('/testapi/storage/Product/Model_List', params)
+// 产品规格
+export const Storehouse_Product_Spec_List = (params: any) => $http.post('/testapi/storage/Product/Spec_List', params)
+// 产品列表
+export const Storehouse_Product_List = (params: any) => $http.post('/testapi/storage/Product/List', params)
+// 产品添加
+export const Storehouse_Product_Add = (params: any) => $http.post('/testapi/storage/Product/Add', params)
+// 产品修改
+export const Storehouse_Product_Edit = (params: any) => $http.post('/testapi/storage/Product/Edit', params)
+// 产品删除
+export const Storehouse_Product_Del = (params: any) => $http.post('/testapi/storage/Product/Del', params)

+ 12 - 12
src/api/workAttendance/index.ts

@@ -5,19 +5,19 @@ import $http from '../index'
 // 我的请假列表
 export const Leave_User_list = (params: any) => $http.post('api/ams/Leave/User_list', params)
 // 请假类型
-export const LeaveType_List = (params: any) => $http.post('api/ams/LeaveType/List', params)
+export const LeaveType_List = (params: any) => $http.post('/api/ams/LeaveType/List', params)
 // 请假审批
-export const Leave_List = (params: any) => $http.post('api/ams/Leave/List', params)
+export const Leave_List = (params: any) => $http.post('/api/ams/Leave/List', params)
 // 请假申请
-export const Leave_Add = (params: any) => $http.post('api/ams/Leave/Add', params)
+export const Leave_Add = (params: any) => $http.post('/api/ams/Leave/Add', params)
 // 扣除-财务权限
-export const Leave_Deduct = (params: any) => $http.post('api/ams/Leave/Deduct', params)
+export const Leave_Deduct = (params: any) => $http.post('/api/ams/Leave/Deduct', params)
 // 编辑
-export const Leave_Edit = (params: any) => $http.post('api/ams/Leave/Edit', params)
+export const Leave_Edit = (params: any) => $http.post('/api/ams/Leave/Edit', params)
 // 审批
-export const Leave_Approval = (params: any) => $http.post('api/ams/Leave/Approval', params)
+export const Leave_Approval = (params: any) => $http.post('/api/ams/Leave/Approval', params)
 // 删除
-export const Leave_Del = (params: any) => $http.post('api/ams/Leave/Del', params)
+export const Leave_Del = (params: any) => $http.post('/api/ams/Leave/Del', params)
 // 请假剩余时长
 export const Leave_DaysOff = (params: any) => $http.post('/api/ams/Leave/DaysOff', params)
 // 财务管理
@@ -27,16 +27,16 @@ export const Leave_Finance_List = (params: any) => $http.post('/api/ams/Leave/Fi
  * 加班
  */
 // 审批列表
-export const Overtime_List = (params: any) => $http.post('api/ams/Overtime/List', params)
+export const Overtime_List = (params: any) => $http.post('/api/ams/Overtime/List', params)
 // 我的加班列表
 export const Overtime_User_list = (params: any) => $http.post('/api/ams/Overtime/User_list', params)
 // 加班申请
-export const Overtime_Add = (params: any) => $http.post('api/ams/Overtime/Add', params)
+export const Overtime_Add = (params: any) => $http.post('/api/ams/Overtime/Add', params)
 // 编辑
-export const Overtime_Edit = (params: any) => $http.post('api/ams/Overtime/Edit', params)
+export const Overtime_Edit = (params: any) => $http.post('/api/ams/Overtime/Edit', params)
 // 审批
-export const Overtime_Approval = (params: any) => $http.post('api/ams/Overtime/Approval', params)
+export const Overtime_Approval = (params: any) => $http.post('/api/ams/Overtime/Approval', params)
 // 删除
-export const Overtime_Del = (params: any) => $http.post('api/ams/Overtime/Del', params)
+export const Overtime_Del = (params: any) => $http.post('/api/ams/Overtime/Del', params)
 // 统计
 export const Overtime_Stat = (params: any) => $http.post('/api/ams/Overtime/Stat', params)

+ 2 - 1
src/components/TableBase/index.vue

@@ -50,7 +50,8 @@ const resize = () => {
     cardHeight = props.onResize()
   } else {
     const height = document.documentElement.clientHeight
-    cardHeight = height - 80 - 12 - 60 - 12
+    const header = document.querySelector('.table-header') as HTMLDivElement
+    cardHeight = height - header.clientHeight - 12 - 60 - 12
   }
 }
 onMounted(() => {

+ 118 - 0
src/components/Upload/index.vue

@@ -0,0 +1,118 @@
+<script setup lang="ts">
+import { ref } from 'vue'
+import { Plus } from '@element-plus/icons-vue'
+import { UpFileToken } from '@/api/public/index'
+import { ElMessage, genFileId } from 'element-plus'
+import { GlobalStore } from '@/stores/index'
+import type { UploadProps, UploadRawFile } from 'element-plus'
+
+const upload = ref()
+const globalStore = GlobalStore()
+
+interface FileListType {
+  url?: string
+  name?: string
+}
+
+interface ProTableProps {
+  isImg?: boolean // 是否只能上传图片
+  disabled?: boolean
+  fileList?: FileListType[]
+  // beforeUpload: () => void
+  // onSuccess: () => Promise<any>
+  // onError: () => Promise<any>
+  // handleExceed: () => void
+  // handleRemove: () => void
+  // handlePictureCardPreview: () => void
+  // uploadData: {
+  //   token: string
+  //   key: string
+  // }
+}
+
+// let prove_img = true
+const dialogImageUrl = ref('')
+const dialogVisible = ref(false)
+const uploadData = {
+  token: '',
+  key: ''
+}
+
+// 图片查看 放大
+const handlePictureCardPreview = async (file: any) => {
+  dialogImageUrl.value = file.url as string
+  dialogVisible.value = true
+}
+// 图片上传之前
+const beforeUpload = async (file: any) => {
+  let reg = /^image/g
+  if (isImg.value && !reg.test(file.type)) {
+    ElMessage.error('必须上传图片!!')
+    return
+  }
+  // prove_img = false
+  let suffix = file.type.split('/')[1]
+  const res: any = await UpFileToken({ User_tokey: globalStore.GET_User_tokey, T_suffix: suffix })
+  uploadData.token = res.Data
+  uploadData.key = file.name
+}
+// 图片上传超出界限
+const handleExceed: UploadProps['onExceed'] = (files: any) => {
+  upload.value.clearFiles()
+  const file = files[0] as UploadRawFile
+  file.uid = genFileId()
+  upload.value.handleStart(file)
+  upload.value.submit()
+}
+// 图片上传成功
+const onSuccess = (response: any) => {
+  // form.value.T_prove_img = response.key
+  // prove_img = true
+  ElMessage.success('图片上传成功!!')
+}
+// 图片上传失败
+const onError = () => {
+  ElMessage.error('图片上传失败!!')
+}
+// 图片移除
+const handleRemove: UploadProps['onRemove'] = () => {
+  // form.value.T_prove_img = ''
+}
+
+// 接受父组件参数,配置默认值
+const props = withDefaults(defineProps<ProTableProps>(), {
+  disabled: true,
+  fileList: () => []
+})
+
+const fileList = ref<FileListType[]>(props.fileList)
+const isImg = ref<boolean>(props.isImg)
+</script>
+
+<template>
+  <div class="upload">
+    <el-upload
+      ref="upload"
+      :disabled="disabled"
+      v-model:file-list="fileList"
+      action="https://up-z2.qiniup.com"
+      list-type="picture-card"
+      :limit="1"
+      :auto-upload="true"
+      :before-upload="beforeUpload"
+      :on-success="onSuccess"
+      :on-error="onError"
+      :on-exceed="handleExceed"
+      :on-remove="handleRemove"
+      :on-preview="handlePictureCardPreview"
+      :data="uploadData"
+    >
+      <el-icon><Plus /></el-icon>
+    </el-upload>
+    <el-dialog v-model="dialogVisible">
+      <img w-full :src="dialogImageUrl" class="full-img" alt="Preview Image" />
+    </el-dialog>
+  </div>
+</template>
+
+<style scoped></style>

+ 24 - 108
src/router/modules/staticRouter.ts

@@ -13,114 +13,30 @@ export const staticRouter: RouteRecordRaw[] = [
       title: '起始页'
     },
     children: [
-      // {
-      //   path: '/home',
-      //   name: 'Home',
-      //   component: () => import('@/views/home/index.vue'),
-      //   meta: {
-      //     title: '首页',
-      //     icon: 'HomeFilled'
-      //   }
-      // }
-      // {
-      //   path: '/roles',
-      //   name: 'Roles',
-      //   component: () => import('@/views/account/roles/Roles.vue'),
-      //   meta: {
-      //     title: '角色管理',
-      //     icon: '\ue648'
-      //   }
-      // },
-      // {
-      //   path: '/users',
-      //   name: 'Users',
-      //   component: () => import('@/views/account/users/Users.vue'),
-      //   meta: {
-      //     title: '账户管理',
-      //     icon: '\ue6a1'
-      //   }
-      // }
-      // {
-      //   path: '/salary',
-      //   name: 'Salary',
-      //   component: () => import('@/views/salary/salary/Salary.vue'),
-      //   meta: {
-      //     title: '薪资管理',
-      //     icon: '\ue7cd'
-      //   }
-      // },
-      // {
-      //   path: '/salaryCount',
-      //   name: 'SalaryCount',
-      //   component: () => import('@/views/salary/SalaryCount.vue'),
-      //   meta: {
-      //     title: '薪资统计',
-      //     icon: '\ue831'
-      //   }
-      // },
-      // {
-      //   path: '/salaryMy',
-      //   name: 'SalaryMy',
-      //   component: () => import('@/views/salary/SalaryMy.vue'),
-      //   meta: {
-      //     title: '我的薪资',
-      //     icon: '\ue7d1'
-      //   }
-      // },
-      // {
-      //   path: '/records',
-      //   name: 'Records',
-      //   component: () => import('@/views/workAttendance/records/Records.vue'),
-      //   meta: {
-      //     title: '统筹管理',
-      //     icon: 'DocumentCopy'
-      //   }
-      // },
-      // {
-      //   path: '/recordsFinance',
-      //   name: 'RecordsFinance',
-      //   component: () => import('@/views/workAttendance/RecordsFinance.vue'),
-      //   meta: {
-      //     title: '统筹管理(财务)',
-      //     icon: 'Notebook'
-      //   }
-      // },
-      // {
-      //   path: '/overtime',
-      //   name: 'Overtime',
-      //   component: () => import('@/views/workAttendance/Overtime.vue'),
-      //   meta: {
-      //     title: '加班审批',
-      //     icon: '\ue690'
-      //   }
-      // },
-      // {
-      //   path: '/leave',
-      //   name: 'Leave',
-      //   component: () => import('../../views/workAttendance/Leave.vue'),
-      //   meta: {
-      //     title: '请假审批',
-      //     icon: '\ue627'
-      //   }
-      // },
-      // {
-      //   path: '/myOvertime',
-      //   name: ' MyOvertime',
-      //   component: () => import('../../views/workAttendance/MyOvertime.vue'),
-      //   meta: {
-      //     title: '我的加班',
-      //     icon: '\ue64c'
-      //   }
-      // },
-      // {
-      //   path: '/myLeave',
-      //   name: 'MyLeave',
-      //   component: () => import('@/views/workAttendance/MyLeave.vue'),
-      //   meta: {
-      //     title: '我的请假',
-      //     icon: '\ue6aa'
-      //   }
-      // }
+      {
+        path: '/list',
+        name: 'List',
+        component: () => import('@/views/storehouse/List.vue'),
+        meta: {
+          title: '仓库列表'
+        }
+      },
+      {
+        path: '/classify',
+        name: 'Classify',
+        component: () => import('@/views/storehouse/Classify.vue'),
+        meta: {
+          title: '产品分类'
+        }
+      },
+      {
+        path: '/productionList',
+        name: 'ProductionList',
+        component: () => import('@/views/storehouse/ProductionList.vue'),
+        meta: {
+          title: '产品列表'
+        }
+      }
     ]
   },
   {

+ 3 - 1
src/style.scss

@@ -31,6 +31,9 @@ body {
 .m-0 {
   margin: 0 !important;
 }
+.m-b-6 {
+  margin-bottom: 24px !important;
+}
 .margin-left-0 {
   margin-left: 0 !important;
 }
@@ -119,5 +122,4 @@ body {
   }
 }
 
-
 @import '@/assets/iconfont.css';

+ 3 - 3
src/utils/common.ts

@@ -39,7 +39,7 @@ export const getAllBreadcrumbList = (menuList: any, result: { [key: string]: any
 }
 
 const path = {
-  home: ["/home"],
+  home: ['/home'],
   roles: ['/roles'],
   users: ['/users'],
   salary: ['/salary'],
@@ -57,9 +57,9 @@ const permissionPath = (permission: string): string => {
     return '/salary'
   } else if (path.salary.includes(permission)) {
     return '/salary/salary'
-  }else if (path.workAttendance.includes(permission)) {
+  } else if (path.workAttendance.includes(permission)) {
     return '/workAttendance'
-  } else if (path.records.includes(permission)) { 
+  } else if (path.records.includes(permission)) {
     return '/workAttendance/records'
   }
   return '/home'

+ 4 - 4
src/views/account/users/Users.vue

@@ -99,19 +99,19 @@ const SearchInfo = () => {
       </template>
       <template #T_name="{ row }">{{ row.T_name }}</template>
       <template #T_sex="{ row }">
-        <el-tag class="ml-2" type="success" v-if="row.T_sex === 1">男</el-tag>
+        <el-tag class="ml-2" type="primary" v-if="row.T_sex === 1">男</el-tag>
         <el-tag class="ml-2" type="danger" v-else>女</el-tag>
       </template>
       <template #T_expire="{ row }">
-        <el-tag class="ml-2" type="success" v-if="row.T_expire === 0">否</el-tag>
+        <el-tag class="ml-2" type="primary" v-if="row.T_expire === 0">否</el-tag>
         <el-tag class="ml-2" type="danger" v-else>是</el-tag>
       </template>
       <template #T_marry="{ row }">
-        <el-tag class="ml-2" type="success" v-if="row.T_marry === 0">未婚</el-tag>
+        <el-tag class="ml-2" type="primary" v-if="row.T_marry === 0">未婚</el-tag>
         <el-tag class="ml-2" type="danger" v-else>已婚</el-tag>
       </template>
       <template #T_entry_type="{ row }">
-        <el-tag class="ml-2" type="success" v-if="+row.T_entry_type === 1">全职</el-tag>
+        <el-tag class="ml-2" type="primary" v-if="+row.T_entry_type === 1">全职</el-tag>
         <el-tag class="ml-2" type="warning" v-else-if="+row.T_entry_type === 2">兼职</el-tag>
         <el-tag class="ml-2" type="danger" v-else>实习生</el-tag>
       </template>

+ 3 - 2
src/views/account/users/components/DrawerFrom.vue

@@ -104,7 +104,8 @@ const AddUser = (formEl: FormInstance | undefined) => {
         form.value.T_pass = md5(form.value.T_pass)
         res = await User_Add(form.value)
       } else {
-        form.value.T_pass === _PASS && (form.value.T_pass = '')
+        if (form.value.T_pass === _PASS) form.value.T_pass = ''
+        else form.value.T_pass = md5(form.value.T_pass)
         res = await User_Edit(form.value)
       }
       if (res.Code === 200) {
@@ -284,7 +285,7 @@ defineExpose({
 
       <el-form-item :label-width="formLabelWidth">
         <el-button v-if="action" color="#626aef" @click="AddUser(formRef)">添加</el-button>
-        <el-button v-else color="#626aef" @click="AddUser(formRef)">编辑</el-button>
+        <el-button v-else color="#626aef" @click="AddUser(formRef)">修改</el-button>
       </el-form-item>
     </el-form>
   </Drawer>

+ 171 - 0
src/views/storehouse/Classify.vue

@@ -0,0 +1,171 @@
+<script setup lang="ts">
+import {
+  Storehouse_ProductClass_List,
+  Storehouse_ProductClass_Add,
+  Storehouse_ProductClass_Edit,
+  Storehouse_ProductClass_Del
+} from '@/api/storehouse/index'
+import { GlobalStore } from '@/stores/index'
+import { ref, reactive, nextTick } from 'vue'
+import Drawer from '@/components/Drawer/index.vue'
+import TableBase from '@/components/TableBase/index.vue'
+import { Edit, Delete } from '@element-plus/icons-vue'
+import { ElMessageBox, ElMessage } from 'element-plus'
+import type { FormInstance, FormRules } from 'element-plus'
+import type { ColumnProps } from '@/components/TableBase/interface/index'
+
+const isNew = ref(true)
+const globalStore = GlobalStore()
+const formLabelWidth = ref('130px')
+const ruleFormRef = ref<FormInstance>()
+const drawerRef = ref<InstanceType<typeof Drawer> | null>(null)
+const TableRef = ref<InstanceType<typeof TableBase> | null>(null)
+const initParam = {
+  User_tokey: globalStore.GET_User_tokey,
+  T_name: ''
+}
+
+const columns: ColumnProps[] = [
+  { type: 'index', label: '序号', width: 80 },
+  { prop: 'T_name', label: '分类名称' },
+  { prop: 'operation', label: '操作', width: 200, fixed: 'right' }
+]
+
+// 添加仓库名称
+type Fn = () => void
+const form = reactive({
+  name: '',
+  id: ''
+})
+
+const rules = reactive<FormRules>({
+  name: [{ required: true, message: '请输入分类名称', trigger: 'blur' }]
+})
+
+const callbackDrawer = (done: Fn) => {
+  resetForm(ruleFormRef.value)
+  done()
+}
+const openDrawer = (type: string, row?: any) => {
+  isNew.value = type === 'new' ? true : false
+  nextTick(() => {
+    !isNew.value && ((form.name = row.T_name), (form.id = row.Id))
+  })
+  drawerRef.value?.openDrawer()
+}
+
+const resetForm = (formEl: FormInstance | undefined) => {
+  if (!formEl) return
+  formEl.resetFields()
+}
+
+const AddUserName = (formEl: FormInstance | undefined) => {
+  if (!formEl) return
+  formEl.validate(async valid => {
+    if (valid) {
+      let res: any = {}
+      if (isNew.value) {
+        res = await Storehouse_ProductClass_Add({ User_tokey: globalStore.GET_User_tokey, T_name: form.name })
+      } else {
+        res = await Storehouse_ProductClass_Edit({
+          User_tokey: globalStore.GET_User_tokey,
+          T_name: form.name,
+          T_id: form.id
+        })
+      }
+      if (res.Code === 200) {
+        ElMessage.success('分类名称添加成功!!')
+        nextTick(() => {
+          drawerRef.value?.closeDrawer()
+          TableRef.value?.getTableList()
+          resetForm(ruleFormRef.value)
+          isNew.value = true
+        })
+      }
+    } else {
+      return false
+    }
+  })
+}
+
+// 删除
+const UserDelete = (row: any) => {
+  ElMessageBox.confirm('您确定要删除分类名称吗?', '警告', {
+    confirmButtonText: '确定',
+    cancelButtonText: '取消',
+    type: 'warning'
+  })
+    .then(async () => {
+      const res: any = await Storehouse_ProductClass_Del({ User_tokey: globalStore.GET_User_tokey, T_id: row.Id })
+      if (res.Code === 200) {
+        ElMessage.success('删除成功!')
+        nextTick(() => {
+          TableRef.value?.getTableList()
+        })
+      }
+    })
+    .catch(() => {
+      ElMessage.warning('取消成功!')
+    })
+}
+
+// 搜索
+const search = ref('')
+const searchHandle = () => {
+  initParam.T_name = search.value
+  TableRef.value?.searchTable()
+}
+</script>
+
+<template>
+  <div class="Classify">
+    <TableBase ref="TableRef" :columns="columns" :requestApi="Storehouse_ProductClass_List" :initParam="initParam">
+      <template #table-header>
+        <div class="input-suffix">
+          <el-row :gutter="20" style="margin-bottom: 0">
+            <el-col :span="12">
+              <span class="inline-flex items-center">产品分类名称:</span>
+              <el-input
+                v-model="search"
+                type="text"
+                class="w-50 m-2"
+                @change="searchHandle"
+                placeholder="按产品分类名称搜索"
+              />
+              <el-button type="primary" @click.enter="searchHandle">搜索</el-button>
+            </el-col>
+            <el-col :span="6" :offset="6"><el-button type="primary" @click="openDrawer('new')">添加</el-button></el-col>
+          </el-row>
+        </div>
+      </template>
+      <template #right="{ row }">
+        <el-button link type="primary" size="small" :icon="Edit" @click="openDrawer('edit', row)">编辑</el-button>
+        <el-button link type="danger" size="small" :icon="Delete" @click="UserDelete(row)">删除</el-button>
+      </template>
+    </TableBase>
+    <Drawer ref="drawerRef" :handleClose="callbackDrawer">
+      <template #header="{ params }">
+        <h4 :id="params.titleId" :class="params.titleClass">{{ isNew ? '添加' : '编辑' }} - 产品名称</h4>
+      </template>
+      <el-form ref="ruleFormRef" :model="form" :rules="rules">
+        <el-divider border-style="dashed" />
+        <el-form-item label="产品分类名称:" :label-width="formLabelWidth" prop="name">
+          <el-input v-model="form.name" type="text" autocomplete="off" placeholder="请输入产品分类名称" />
+        </el-form-item>
+        <el-form-item :label-width="formLabelWidth">
+          <el-button v-if="isNew" color="#626aef" @click="AddUserName(ruleFormRef)">提交</el-button>
+          <el-button v-else color="#626aef" @click="AddUserName(ruleFormRef)">修改</el-button>
+        </el-form-item>
+      </el-form>
+    </Drawer>
+  </div>
+</template>
+
+<style scoped lang="scss">
+.input-suffix {
+  width: 100%;
+  .w-50 {
+    width: 12.5rem;
+  }
+}
+</style>

+ 7 - 0
src/views/storehouse/IoTNetworkCard.vue

@@ -0,0 +1,7 @@
+<script setup lang="ts"></script>
+
+<template>
+  <div class="classify">物联网卡列表</div>
+</template>
+
+<style scoped></style>

+ 167 - 0
src/views/storehouse/List.vue

@@ -0,0 +1,167 @@
+<script setup lang="ts">
+import {
+  Storehouse_Depot_List,
+  Storehouse_Depot_Add,
+  Storehouse_Depot_Edit,
+  Storehouse_Depot_Del
+} from '@/api/storehouse/index'
+import { GlobalStore } from '@/stores/index'
+import { ref, reactive, nextTick } from 'vue'
+import Drawer from '@/components/Drawer/index.vue'
+import TableBase from '@/components/TableBase/index.vue'
+import type { FormInstance, FormRules } from 'element-plus'
+import { Edit, Delete } from '@element-plus/icons-vue'
+import type { ColumnProps } from '@/components/TableBase/interface/index'
+import { ElMessageBox, ElMessage } from 'element-plus'
+
+const isNew = ref(true)
+const globalStore = GlobalStore()
+const formLabelWidth = ref('100px')
+const ruleFormRef = ref<FormInstance>()
+const drawerRef = ref<InstanceType<typeof Drawer> | null>(null)
+const TableRef = ref<InstanceType<typeof TableBase> | null>(null)
+const initParam = {
+  User_tokey: globalStore.GET_User_tokey,
+  T_name: ''
+}
+
+const columns: ColumnProps[] = [
+  { type: 'index', label: '序号', width: 80 },
+  { prop: 'T_name', label: '仓库名称' },
+  { prop: 'operation', label: '操作', width: 200, fixed: 'right' }
+]
+
+// 添加仓库名称
+type Fn = () => void
+const form = reactive({
+  name: '',
+  id: ''
+})
+
+const rules = reactive<FormRules>({
+  name: [{ required: true, message: '请输入仓库名称', trigger: 'blur' }]
+})
+
+const callbackDrawer = (done: Fn) => {
+  resetForm(ruleFormRef.value)
+  done()
+}
+const openDrawer = (type: string, row?: any) => {
+  isNew.value = type === 'new' ? true : false
+  nextTick(() => {
+    !isNew.value && ((form.name = row.T_name), (form.id = row.Id))
+  })
+  drawerRef.value?.openDrawer()
+}
+
+const resetForm = (formEl: FormInstance | undefined) => {
+  if (!formEl) return
+  formEl.resetFields()
+}
+
+const AddUserName = (formEl: FormInstance | undefined) => {
+  if (!formEl) return
+  formEl.validate(async valid => {
+    if (valid) {
+      let res: any = {}
+      if (isNew.value) {
+        res = await Storehouse_Depot_Add({ User_tokey: globalStore.GET_User_tokey, T_name: form.name })
+      } else {
+        res = await Storehouse_Depot_Edit({ User_tokey: globalStore.GET_User_tokey, T_name: form.name, T_id: form.id })
+      }
+      if (res.Code === 200) {
+        ElMessage.success('添加仓库名称成功!!')
+        nextTick(() => {
+          drawerRef.value?.closeDrawer()
+          TableRef.value?.getTableList()
+          resetForm(ruleFormRef.value)
+          isNew.value = true
+        })
+      }
+    } else {
+      return false
+    }
+  })
+}
+
+// 删除
+const UserDelete = (row: any) => {
+  ElMessageBox.confirm('您确定要删除该仓库名称吗?', '警告', {
+    confirmButtonText: '确定',
+    cancelButtonText: '取消',
+    type: 'warning'
+  })
+    .then(async () => {
+      const res: any = await Storehouse_Depot_Del({ User_tokey: globalStore.GET_User_tokey, T_id: row.Id })
+      if (res.Code === 200) {
+        ElMessage.success('删除成功!')
+        nextTick(() => {
+          TableRef.value?.getTableList()
+        })
+      }
+    })
+    .catch(() => {
+      ElMessage.warning('取消成功!')
+    })
+}
+
+// 搜索
+const search = ref('')
+const searchHandle = () => {
+  initParam.T_name = search.value
+  TableRef.value?.searchTable()
+}
+</script>
+
+<template>
+  <div class="list">
+    <TableBase ref="TableRef" :columns="columns" :requestApi="Storehouse_Depot_List" :initParam="initParam">
+      <template #table-header>
+        <div class="input-suffix">
+          <el-row :gutter="20" style="margin-bottom: 0">
+            <el-col :span="12">
+              <span class="inline-flex items-center">仓库名称:</span>
+              <el-input
+                v-model="search"
+                type="text"
+                class="w-50 m-2"
+                @change="searchHandle"
+                placeholder="按仓库名称搜索"
+              />
+              <el-button type="primary" @click="searchHandle">搜索</el-button>
+            </el-col>
+            <el-col :span="6" :offset="6"><el-button type="primary" @click="openDrawer('new')">添加</el-button></el-col>
+          </el-row>
+        </div>
+      </template>
+      <template #right="{ row }">
+        <el-button link type="primary" size="small" :icon="Edit" @click="openDrawer('edit', row)">编辑</el-button>
+        <el-button link type="danger" size="small" :icon="Delete" @click="UserDelete(row)">删除</el-button>
+      </template>
+    </TableBase>
+    <Drawer ref="drawerRef" :handleClose="callbackDrawer">
+      <template #header="{ params }">
+        <h4 :id="params.titleId" :class="params.titleClass">{{ isNew ? '添加' : '编辑' }} - 仓库名称</h4>
+      </template>
+      <el-form ref="ruleFormRef" :model="form" :rules="rules">
+        <el-divider border-style="dashed" />
+        <el-form-item label="仓库名称:" :label-width="formLabelWidth" prop="name">
+          <el-input v-model="form.name" type="text" autocomplete="off" placeholder="请输入仓库名称" />
+        </el-form-item>
+        <el-form-item :label-width="formLabelWidth">
+          <el-button v-if="isNew" color="#626aef" @click="AddUserName(ruleFormRef)">提交</el-button>
+          <el-button v-else color="#626aef" @click="AddUserName(ruleFormRef)">修改</el-button>
+        </el-form-item>
+      </el-form>
+    </Drawer>
+  </div>
+</template>
+
+<style scoped lang="scss">
+.input-suffix {
+  width: 100%;
+  .w-50 {
+    width: 12.5rem;
+  }
+}
+</style>

+ 169 - 0
src/views/storehouse/ProductionList.vue

@@ -0,0 +1,169 @@
+<script setup lang="ts">
+import {
+  Storehouse_ProductClass_List,
+  Storehouse_Product_List,
+  Storehouse_Product_Add,
+  Storehouse_Product_Edit,
+  Storehouse_Product_Del,
+  Storehouse_Product_Spec_List
+} from '@/api/storehouse/index'
+import { GlobalStore } from '@/stores/index'
+import { ref, reactive, nextTick, onMounted } from 'vue'
+import Drawer from '@/components/Drawer/index.vue'
+import TableBase from '@/components/TableBase/index.vue'
+import type { FormInstance, FormRules } from 'element-plus'
+import { Edit, Delete } from '@element-plus/icons-vue'
+import type { ColumnProps } from '@/components/TableBase/interface/index'
+import { ElNotification, ElMessageBox, ElMessage } from 'element-plus'
+import Upload from '@/components/Upload/index.vue'
+
+const isNew = ref(true)
+const globalStore = GlobalStore()
+const formLabelWidth = ref('100px')
+const drawerRef = ref<InstanceType<typeof Drawer> | null>(null)
+const TableRef = ref<InstanceType<typeof TableBase> | null>(null)
+
+const initParam = {
+  User_tokey: globalStore.GET_User_tokey,
+  T_name: ''
+}
+
+const columns: ColumnProps[] = [
+  { type: 'index', label: '序号', width: 80 },
+  { prop: 'T_img', label: '产品图片' },
+  { prop: 'T_name', label: '产品名称' },
+  { prop: 'T_class_name', label: '产品分类' },
+  { prop: 'T_model', label: '产品型号' },
+  { prop: 'T_spec', label: '产品规格' },
+  { prop: 'T_relation_sn', label: '关联SN' },
+  { prop: 'T_name', label: '更新时间' },
+  { prop: 'operation', label: '操作', width: 150, fixed: 'right' }
+]
+
+const rules = reactive<FormRules>({
+  name: [{ required: true, message: '请输入仓库名称', trigger: 'blur' }]
+})
+const form = reactive({
+  T_name: '',
+  T_class: '',
+  T_model: '',
+  T_spec: '',
+  T_relation_sn: '',
+  T_img: '',
+  T_remark: ''
+})
+
+const openDrawer = (type: string, row?: any) => {
+  isNew.value = type === 'new' ? true : false
+  // nextTick(() => {
+  //   !isNew.value && ((form.name = row.T_name), (form.id = row.Id))
+  // })
+  drawerRef.value?.openDrawer()
+}
+const UserDelete = (row: any) => {
+  //
+}
+
+const callbackDrawer = () => {}
+
+// 搜索
+const search = reactive({
+  T_name: '',
+  T_class_name: ''
+})
+const searchHandle = () => {
+  //
+}
+
+// 获取产品分类
+const options = ref<any[]>([])
+const getProductClassList = async () => {
+  const res: any = await Storehouse_ProductClass_List({ page: 1, page_z: 999 })
+  options.value = res.Data.Data
+}
+
+onMounted(() => {
+  getProductClassList()
+})
+</script>
+
+<template>
+  <div class="production-list">
+    <TableBase ref="TableRef" :columns="columns" :requestApi="Storehouse_Product_List" :initParam="initParam">
+      <template #table-header>
+        <div class="input-suffix">
+          <el-row :gutter="20" style="margin-bottom: 0">
+            <el-col :xl="6" :lg="8" :md="10">
+              <span class="inline-flex items-center">产品分类:</span>
+              <el-select v-model="search.T_class_name" class="w-50 m-2" placeholder="请选择分类~">
+                <el-option v-for="item in options" :key="item.Id" :label="item.T_name" :value="item.Id" />
+              </el-select>
+            </el-col>
+            <el-col :xl="10" :md="12">
+              <span class="inline-flex items-center">产品名称:</span>
+              <el-input v-model="search.T_name" type="text" class="w-50 m-2" placeholder="按产品名称、产品型号搜索" />
+              <el-button type="primary" @click="searchHandle">搜索</el-button>
+            </el-col>
+            <el-col :xl="6" :md="2" class="btn"
+              ><el-button type="primary" @click="openDrawer('new')">添加</el-button></el-col
+            >
+          </el-row>
+        </div>
+      </template>
+      <template #right="{ row }">
+        <el-button link type="primary" size="small" :icon="Edit" @click="openDrawer('edit', row)">编辑</el-button>
+        <el-button link type="danger" size="small" :icon="Delete" @click="UserDelete(row)">删除</el-button>
+      </template>
+    </TableBase>
+    <Drawer ref="drawerRef" :handleClose="callbackDrawer">
+      <template #header="{ params }">
+        <h4 :id="params.titleId" :class="params.titleClass">{{ isNew ? '添加' : '编辑' }} - 产品</h4>
+      </template>
+      <el-form ref="ruleFormRef" :model="form" :rules="rules">
+        <el-divider border-style="dashed" />
+        <el-form-item label="产品名称:" class="m-b-6" :label-width="formLabelWidth" prop="name">
+          <el-input v-model="form.T_name" type="text" autocomplete="off" placeholder="请输入产品名称" />
+        </el-form-item>
+        <el-form-item label="产品分类:" class="m-b-6" :label-width="formLabelWidth" prop="name">
+          <el-select v-model="form.T_class" placeholder="请选择产品分类~">
+            <el-option v-for="item in options" :key="item.Id" :label="item.T_name" :value="item.Id" />
+          </el-select>
+        </el-form-item>
+        <el-form-item label="产品型号:" class="m-b-6" :label-width="formLabelWidth" prop="name">
+          <el-input v-model="form.T_name" type="text" autocomplete="off" placeholder="请输入产品型号" />
+        </el-form-item>
+        <el-form-item label="产品规格:" class="m-b-6" :label-width="formLabelWidth" prop="name">
+          <el-select v-model="form.T_class" placeholder="请选择产品规格~">
+            <el-option v-for="item in options" :key="item.Id" :label="item.T_name" :value="item.Id" />
+          </el-select>
+        </el-form-item>
+        <el-form-item label="产品图片:" class="m-b-6" :label-width="formLabelWidth" prop="name">
+          <Upload></Upload>
+        </el-form-item>
+        <!-- <el-form-item :label-width="formLabelWidth">
+          <el-button v-if="isNew" color="#626aef" @click="AddUserName(ruleFormRef)">提交</el-button>
+          <el-button v-else color="#626aef" @click="AddUserName(ruleFormRef)">修改</el-button>
+        </el-form-item> -->
+      </el-form>
+    </Drawer>
+  </div>
+</template>
+
+<style scoped lang="scss">
+.production-list {
+  height: 100%;
+  .input-suffix {
+    width: 100%;
+    .inline-flex {
+      white-space: nowrap;
+    }
+    .btn {
+      display: flex;
+      justify-content: end;
+    }
+    .w-50 {
+      width: 12.5rem;
+    }
+  }
+}
+</style>

+ 10 - 4
src/views/workAttendance/MyOvertime.vue

@@ -39,7 +39,7 @@ const columns: ColumnProps[] = [
   { prop: 'T_end_time', label: '结束时间', ellipsis: true },
   { prop: 'T_duration', label: '时长', width: '100px', name: 'T_duration' },
   { prop: 'T_State', label: '审核', width: '100px', name: 'T_State' },
-  { prop: 'operation', label: '操作', width: 150, fixed: 'right' }
+  { prop: 'operation', label: '操作', width: 200, fixed: 'right' }
 ]
 const columns_Stat: ColumnProps[] = [
   { prop: 'T_duration', label: '时长', width: '100px', name: 'T_duration' },
@@ -270,7 +270,7 @@ const handleRemove: UploadProps['onRemove'] = () => {
         </template>
         <template #right="{ row }">
           <el-button
-            v-if="row.T_State !== 1"
+            :disabled="row.T_State === 1"
             link
             type="primary"
             size="small"
@@ -279,7 +279,7 @@ const handleRemove: UploadProps['onRemove'] = () => {
             >编辑</el-button
           >
           <el-button
-            v-if="row.T_State !== 1"
+            :disabled="row.T_State === 1"
             link
             type="danger"
             size="small"
@@ -287,7 +287,13 @@ const handleRemove: UploadProps['onRemove'] = () => {
             @click="OvertimeDelete(row)"
             >删除</el-button
           >
-          <el-button v-if="row.T_State === 1" link type="success" size="small" :icon="View" @click="OvertimeView(row)"
+          <el-button
+            :disabled="row.T_State !== 1"
+            link
+            type="success"
+            size="small"
+            :icon="View"
+            @click="OvertimeView(row)"
             >查看</el-button
           >
         </template>

+ 4 - 4
vite.config.ts

@@ -26,11 +26,11 @@ export default defineConfig(({ mode }: ConfigEnv): UserConfig => {
       proxy: {
         '/api': {
           target: 'https://erp.baozhida.cn',
-          changeOrigin: true
-          // rewrite: path => path.replace(/^\/api/, '')
+          changeOrigin: true,
+          rewrite: path => path.replace(/^\/api/, '/testapi')
         },
-        '/salary': {
-          target: 'http://erp.baozhida.cn',
+        '/testapi': {
+          target: 'https://erp.baozhida.cn',
           changeOrigin: true
         },
         '/ams': {