liuhairui 2 tygodni temu
rodzic
commit
d42dcc93cb

+ 59 - 0
src/api/yunyin/product.js

@@ -0,0 +1,59 @@
+import service from '@/utils/request'
+
+//产品基本资料管理
+//新增产品资料
+export const ProductAdd = (data) => {
+    return service({
+        url: '/mes_server/Product/ProductAdd',
+        method: 'post',
+        data
+    })
+}
+//获取左侧菜单产品分类列表
+export const ProductTypeMenu = (params) => {
+    return service({
+        url: '/mes_server/Product/ProductTypeMenu',
+        method: 'get',
+        params
+    })
+}
+//获取产品资料
+export const ProductList = (params) => {
+    return service({
+        url: '/mes_server/Product/ProductList',
+        method: 'get',
+        params
+    })
+}
+//修改产品资料
+export const ProductEdit = (data) => {
+    return service({
+        url: '/mes_server/Product/ProductEdit',
+        method: 'post',
+        data
+    })
+}
+//删除产品资料
+export const ProductDelete = (data) => {
+    return service({
+        url: '/mes_server/Product/ProductDelete',
+        method: 'post',
+        data
+    })
+}
+//获取产品工艺资料列表
+export const ProductGyList = (params) => {
+    return service({
+        url: '/mes_server/Product/ProductGyList',
+        method: 'get',
+        params
+    })
+}
+//获取产品部件资料列表
+export const ProductPartList = (params) => {
+    return service({
+        url: '/mes_server/Product/ProductPartList',
+        method: 'get',
+        params
+    })
+}

+ 34 - 7
src/api/yunyin/yunying.js

@@ -1,6 +1,6 @@
 import service from '@/utils/request'
 
-/** 员工基本资料管理 */
+//员工基本资料管理
 //1.获取部门列表
 export const getDepartment = (data) => {
     return service({
@@ -25,22 +25,49 @@ export const getStaffInfo = (params) => {
         params
     })
 }
-//3.修改员工资料
-export const ygjbzledit = (data) => {
+//4.修改员工资料
+export const PostStaffEdit = (data) => {
     return service({
-        url: '/mes_server/staff/edit',
+        url: '/mes_server/staff/PostStaffEdit',
         method: 'post',
         data
     })
 }
-//4.设置法定天数
-export const clockUpdate = (data) => {
+//5.新增员工资料
+export const PostStaffAdd = (data) => {
     return service({
-        url: '/mes_server/staff/clockUpdate',
+        url: '/mes_server/staff/PostStaffAdd',
         method: 'post',
         data
     })
 }
+//6.删除员工资料(按主键 id)
+export const PostStaffDelete = (data) => {
+    return service({
+        url: '/mes_server/staff/PostStaffDelete',
+        method: 'post',
+        data
+    })
+}
+// 获取工序库列表
+export const GetProcessesList = (params) => {
+    return service({
+        url: '/mes_server/staff/GetProcessesList',
+        method: 'get',
+        params
+    })
+}
+// 获取设备编组
+export const GetDeviceNameList = (params) => {
+    return service({
+        url: '/mes_server/Staff/GetDeviceNameList',
+        method: 'get',
+        params
+    })
+}
+
+
+
 
 /** 产品管理 */
 //1.获取客户信息

+ 447 - 0
src/view/yunyin/product/list.vue

@@ -0,0 +1,447 @@
+<template>
+  <div>
+    <layout>
+      <layout-header>
+        <div class="product-header">
+          <el-input
+            v-model="searchKeyword"
+            placeholder="搜索产品编号或名称"
+            clearable
+            style="width: 220px; margin: 5px"
+            @keyup.enter="onSearch"
+            @clear="onSearch"
+          />
+          <el-button type="primary" icon="Search" style="margin: 5px" @click="onSearch">查询</el-button>
+        </div>
+      </layout-header>
+
+      <layout>
+        <layout-sider :resize-directions="['right']" :width="240" style="margin-right: 10px">
+          <div class="product-menu-wrap">
+            <h3 class="product-menu-title">产品分类</h3>
+            <el-tree
+              ref="menuTreeRef"
+              :data="menuTreeData"
+              class="treecolor product-menu-tree"
+              :props="treeProps"
+              node-key="id"
+              default-expand-all
+              highlight-current
+              @node-click="handleNodeClick"
+            >
+              <template #default="{ data }">
+                <span class="tree-node-text">{{ data.label }}</span>
+              </template>
+            </el-tree>
+          </div>
+        </layout-sider>
+
+        <layout-content>
+          <el-main class="product-main">
+            <div class="gva-table-box product-split">
+              <div class="product-list-block">
+                <el-table
+                  :data="tableData"
+                  border
+                  size="small"
+                  style="width: 100%"
+                  :height="340"
+                  row-key="id"
+                  :show-overflow-tooltip="true"
+                  highlight-current-row
+                  @row-click="onProductRowClick"
+                >
+                  <el-table-column align="center" label="产品编号" prop="product_code" width="120" />
+                  <el-table-column align="left" label="产品名称" prop="product_name" width="200" show-overflow-tooltip />
+                  <el-table-column align="center" label="单位" prop="unit" width="72" />
+                  <el-table-column align="center" label="产品类型" prop="product_type" width="100" />
+                  <el-table-column align="center" label="操作人" prop="Sys_id" width="100" />
+                  <el-table-column align="center" label="创建时间" prop="Sys_rq" width="160" />
+                  <el-table-column align="center" label="修改时间" prop="mod_rq" width="160" />
+                </el-table>
+                <div class="gva-pagination">
+                  <el-pagination
+                    v-model:current-page="page"
+                    v-model:page-size="pageSize"
+                    :page-sizes="[10, 20, 50, 100]"
+                    :total="total"
+                    layout="total, sizes, prev, pager, next, jumper"
+                    background
+                    @current-change="fetchProductList"
+                    @size-change="onPageSizeChange"
+                  />
+                </div>
+              </div>
+
+              <div class="product-detail-block">
+                <div v-if="!selectedRow" class="detail-empty">请在上方列表中点击一行产品,查看部件资料与工艺资料</div>
+                <el-tabs v-else v-model="detailTab" type="border-card" class="product-detail-tabs">
+                  <el-tab-pane label="部件资料" name="part">
+                    <el-table
+                      :data="partList"
+                      border
+                      size="small"
+                      max-height="260"
+                      row-key="id"
+                      :show-overflow-tooltip="true"
+                    >
+                      <el-table-column align="center" label="部件代号" prop="part_code" width="110" />
+                      <el-table-column align="left" label="部件名称" prop="part_name" min-width="120" />
+                      <el-table-column align="center" label="规格" prop="part_spec" width="100" />
+                      <el-table-column align="center" label="数量" prop="qty" width="72" />
+                      <el-table-column align="center" label="操作人" prop="Sys_id" width="100" />
+                      <el-table-column align="center" label="创建时间" prop="Sys_rq" width="160" />
+                      <el-table-column align="center" label="修改时间" prop="mod_rq" width="160" />
+                    </el-table>
+                    <div class="gva-pagination detail-pagination">
+                      <el-pagination
+                        v-model:current-page="partPage"
+                        v-model:page-size="partPageSize"
+                        :page-sizes="[10, 20, 30, 50]"
+                        :total="partTotal"
+                        small
+                        background
+                        layout="total, sizes, prev, pager, next"
+                        @current-change="fetchPartList"
+                        @size-change="onPartPageSizeChange"
+                      />
+                    </div>
+                  </el-tab-pane>
+                  <el-tab-pane label="工艺资料" name="gy">
+                    <el-table
+                      :data="gyList"
+                      border
+                      size="small"
+                      max-height="260"
+                      row-key="id"
+                      :show-overflow-tooltip="true"
+                    >
+                      <el-table-column align="center" label="工艺代号" prop="gy_code" width="110" />
+                      <el-table-column align="left" label="工艺名称" prop="gy_name" min-width="140" />
+                      <el-table-column align="center" label="生产工序" prop="big_process" width="100" />
+                      <el-table-column align="right" label="标准工时" prop="standard_hour" width="96" />
+                      <el-table-column align="right" label="标准工分" prop="standard_score" width="96" />
+                      <el-table-column align="center" label="排序" prop="sort" width="72" />
+                      <el-table-column align="center" label="创建时间" prop="createtime" width="160" />
+                      <el-table-column align="center" label="更新时间" prop="updatetime" width="160" />
+                    </el-table>
+                    <div class="gva-pagination detail-pagination">
+                      <el-pagination
+                        v-model:current-page="gyPage"
+                        v-model:page-size="gyPageSize"
+                        :page-sizes="[10, 20, 30, 50]"
+                        :total="gyTotal"
+                        small
+                        background
+                        layout="total, sizes, prev, pager, next"
+                        @current-change="fetchGyList"
+                        @size-change="onGyPageSizeChange"
+                      />
+                    </div>
+                  </el-tab-pane>
+                </el-tabs>
+              </div>
+            </div>
+          </el-main>
+        </layout-content>
+      </layout>
+    </layout>
+  </div>
+</template>
+
+<script setup>
+import { Layout, LayoutSider, LayoutContent } from '@arco-design/web-vue'
+import { ref, computed, onMounted, nextTick } from 'vue'
+import { ProductTypeMenu, ProductList, ProductPartList, ProductGyList } from '@/api/yunyin/product'
+import { ElMessage } from 'element-plus'
+
+defineOptions({ name: 'ProductList' })
+
+const menuTreeRef = ref(null)
+const treeProps = { label: 'label', children: 'children' }
+const menuTreeData = ref([])
+const tableData = ref([])
+const total = ref(0)
+const page = ref(1)
+const pageSize = ref(30)
+const searchKeyword = ref('')
+
+/** 左侧选中:null 全部 | { type:'category', searchText } | { type:'product', searchText } —— 请求只带 search */
+const menuFilter = ref(null)
+
+const selectedRow = ref(null)
+const detailTab = ref('part')
+
+const partList = ref([])
+const partTotal = ref(0)
+const partPage = ref(1)
+const partPageSize = ref(30)
+
+const gyList = ref([])
+const gyTotal = ref(0)
+const gyPage = ref(1)
+const gyPageSize = ref(30)
+
+
+/** 接口 data: [{ name, list: [{ id, product_code, product_name }] }] */
+const buildMenuTree = (data) => {
+  const root = [
+    {
+      id: 'all-products',
+      label: '全部产品',
+      isAll: true,
+    },
+  ]
+  if (!Array.isArray(data)) return root
+  const cats = data.map((cat, idx) => ({
+    id: `cat-${idx}-${cat.name}`,
+    label: cat.name,
+    isCategory: true,
+    product_type: cat.name,
+    children: (cat.list || []).map((p) => ({
+      id: `prod-${p.id}`,
+      label: p.product_name,
+      isProduct: true,
+      product_name: p.product_name,
+    })),
+  }))
+  return [...root, ...cats]
+}
+
+const loadMenu = async () => {
+  try {
+    const res = await ProductTypeMenu()
+    if (res?.code !== 0) {
+      ElMessage.error(res?.msg || '获取产品分类失败')
+      menuTreeData.value = buildMenuTree([])
+      return
+    }
+    menuTreeData.value = buildMenuTree(res.data)
+    await nextTick()
+    menuTreeRef.value?.setCurrentKey('all-products')
+  } catch (e) {
+    console.error(e)
+    menuTreeData.value = buildMenuTree([])
+    ElMessage.error('获取产品分类失败')
+  }
+}
+
+const fetchProductList = async () => {
+  try {
+    const params = {
+      page: page.value,
+      limit: pageSize.value,
+    }
+    const kw = searchKeyword.value.trim()
+    const f = menuFilter.value
+
+    // 左侧与顶部筛选统一只传 search(不传 product_type)
+    if (f?.type === 'category' || f?.type === 'product') {
+      params.search = f.searchText ?? ''
+    } else if (kw) {
+      params.search = kw
+    }
+
+    const res = await ProductList(params)
+    if (res?.code !== 0) {
+      ElMessage.error(res?.msg || '获取产品列表失败')
+      tableData.value = []
+      total.value = 0
+      return
+    }
+    const payload = res.data || {}
+    tableData.value = Array.isArray(payload.list) ? payload.list : []
+    const c = payload.count ?? payload.total
+    total.value = c != null ? Number(c) : tableData.value.length
+  } catch (e) {
+    console.error(e)
+    tableData.value = []
+    total.value = 0
+    ElMessage.error('获取产品列表失败')
+  }
+}
+
+const handleNodeClick = (data) => {
+  if (data.isAll) {
+    menuFilter.value = null
+  } else if (data.isCategory) {
+    menuFilter.value = { type: 'category', searchText: data.product_type }
+  } else if (data.isProduct) {
+    menuFilter.value = {
+      type: 'product',
+      searchText: data.product_name ?? data.label,
+    }
+  } else {
+    menuFilter.value = null
+  }
+
+  page.value = 1
+  fetchProductList()
+}
+
+const onSearch = () => {
+  page.value = 1
+  fetchProductList()
+}
+
+const onPageSizeChange = () => {
+  page.value = 1
+  fetchProductList()
+}
+
+const fetchPartList = async () => {
+  const code = selectedRow.value?.product_code
+  if (!code) {
+    partList.value = []
+    partTotal.value = 0
+    return
+  }
+  try {
+    const res = await ProductPartList({
+      product_code: code,
+      page: partPage.value,
+      limit: partPageSize.value,
+    })
+    if (res?.code !== 0) {
+      partList.value = []
+      partTotal.value = 0
+      return
+    }
+    const payload = res.data || {}
+    partList.value = Array.isArray(payload.list) ? payload.list : []
+    const c = payload.count ?? payload.total
+    partTotal.value = c != null ? Number(c) : partList.value.length
+  } catch (e) {
+    console.error(e)
+    partList.value = []
+    partTotal.value = 0
+  }
+}
+
+const fetchGyList = async () => {
+  const code = selectedRow.value?.product_code
+  if (!code) {
+    gyList.value = []
+    gyTotal.value = 0
+    return
+  }
+  try {
+    const res = await ProductGyList({
+      product_code: code,
+      page: gyPage.value,
+      limit: gyPageSize.value,
+    })
+    if (res?.code !== 0) {
+      gyList.value = []
+      gyTotal.value = 0
+      return
+    }
+    const payload = res.data || {}
+    gyList.value = Array.isArray(payload.list) ? payload.list : []
+    const c = payload.count ?? payload.total
+    gyTotal.value = c != null ? Number(c) : gyList.value.length
+  } catch (e) {
+    console.error(e)
+    gyList.value = []
+    gyTotal.value = 0
+  }
+}
+
+const onProductRowClick = (row) => {
+  selectedRow.value = row
+  partPage.value = 1
+  gyPage.value = 1
+  detailTab.value = 'part'
+  fetchPartList()
+  fetchGyList()
+}
+
+const onPartPageSizeChange = () => {
+  partPage.value = 1
+  fetchPartList()
+}
+
+const onGyPageSizeChange = () => {
+  gyPage.value = 1
+  fetchGyList()
+}
+
+onMounted(async () => {
+  await loadMenu()
+  menuFilter.value = null
+  await fetchProductList()
+})
+</script>
+
+<style scoped>
+.product-header {
+  padding: 4px 0;
+}
+.product-menu-wrap {
+  background: #fff;
+  padding: 10px;
+  min-height: 260px;
+  max-height: calc(100vh - 140px);
+  overflow: auto;
+}
+.product-menu-title {
+  font-size: 15px;
+  font-weight: 700;
+  margin: 0 0 10px;
+}
+.tree-node-text {
+  font-size: 13px;
+}
+/* 自定义插槽时无 .el-tree-node__label,用 is-current + .tree-node-text;勿用 DOM 改色 */
+.product-menu-wrap :deep(.product-menu-tree.el-tree .el-tree-node.is-current > .el-tree-node__content) {
+  color: red;
+}
+.product-menu-wrap :deep(.product-menu-tree.el-tree .el-tree-node.is-current > .el-tree-node__content .tree-node-text) {
+  color: red;
+  font-weight: 600;
+}
+.filter-hint {
+  font-size: 13px;
+  color: #606266;
+  margin-bottom: 10px;
+}
+.gva-pagination {
+  margin-top: 12px;
+}
+.product-main {
+  padding-bottom: 8px;
+}
+.product-split {
+  display: flex;
+  flex-direction: column;
+  gap: 12px;
+  min-height: 0;
+}
+.product-list-block {
+  flex-shrink: 0;
+}
+.product-detail-block {
+  flex: 1;
+  min-height: 200px;
+}
+.detail-empty {
+  padding: 24px;
+  text-align: center;
+  color: #909399;
+  font-size: 14px;
+  background: #fafafa;
+  border: 1px dashed #dcdfe6;
+  border-radius: 4px;
+}
+.product-detail-tabs {
+  width: 100%;
+}
+.product-detail-tabs :deep(.el-tabs__content) {
+  padding-top: 8px;
+}
+.detail-pagination {
+  margin-top: 10px;
+  display: flex;
+  justify-content: flex-end;
+}
+</style>

+ 282 - 0
src/view/yunyin/renliziyuan/GroupManagement.vue

@@ -0,0 +1,282 @@
+<template>
+  <div>
+    <layout>
+      <layout>
+        <layout-sider :resize-directions="['right']" :width="220" style="margin-right: 10px">
+          <div class="group-tree-wrap">
+            <h3 class="group-tree-title">设备编组</h3>
+            <el-tree
+              ref="treeRef"
+              :data="groupTreeData"
+              :props="treeProps"
+              node-key="id"
+              default-expand-all
+              highlight-current
+              @node-click="onTreeNodeClick"
+            >
+              <template #default="{ data }">
+                <span class="tree-node-text">{{ data.label }}</span>
+              </template>
+            </el-tree>
+          </div>
+        </layout-sider>
+        <layout-content>
+          <el-main>
+            <div class="gva-table-box">
+              <div class="filter-row">
+                <span v-if="filterHint" class="filter-hint">{{ filterHint }}</span>
+                <el-button v-if="selectedFilter" link type="primary" size="small" @click="clearFilter">显示全部</el-button>
+              </div>
+              <el-table
+                :data="displayList"
+                border
+                size="small"
+                style="width: 100%"
+                :height="tableHeight"
+                row-key="UniqId"
+                :show-overflow-tooltip="true"
+              >
+                <el-table-column align="center" label="MAC地址" prop="sys_sbID" min-width="200" />
+                <el-table-column align="center" label="设备编号" prop="设备编号" width="110" />
+                <el-table-column align="center" label="设备名称" prop="设备名称" width="100" />
+                <el-table-column align="center" label="生产工序" prop="生产工序" width="100" />
+                <el-table-column align="center" label="设备编组" prop="设备编组" width="120" />
+                <el-table-column align="center" label="组长" prop="组长" width="120" />
+                <el-table-column align="center" label="状态" prop="status" width="88">
+                  <template #default="{ row }">
+                    <el-tag :type="row.status === '1' ? 'success' : 'danger'" size="small">
+                      {{ row.status === '1' ? '正常' : '异常' }}
+                    </el-tag>
+                  </template>
+                </el-table-column>
+              </el-table>
+              <div class="gva-pagination">
+                <span class="total-text">共 {{ displayList.length }} 条</span>
+              </div>
+            </div>
+          </el-main>
+        </layout-content>
+      </layout>
+    </layout>
+  </div>
+</template>
+
+<script setup>
+import { Layout, LayoutSider, LayoutContent } from '@arco-design/web-vue'
+import { ref, computed, onMounted, nextTick } from 'vue'
+import { getMachineDeviceTypes } from '@/api/mes/job'
+import { ElMessage } from 'element-plus'
+
+defineOptions({ name: 'GroupManagement' })
+
+const treeRef = ref(null)
+const treeProps = { label: 'label', children: 'children' }
+const rawList = ref([])
+const groupTreeData = ref([])
+
+/** 当前筛选:仅工序 / 工序+编组 */
+const selectedFilter = ref(null)
+
+const tableHeight = 'calc(100vh - 220px)'
+
+/** 工序字段比较:数值优先从小到大,否则按字符串含数字规则 */
+const compareProcessField = (a, b) => {
+  const na = Number(a?.['工序'])
+  const nb = Number(b?.['工序'])
+  if (!Number.isNaN(na) && !Number.isNaN(nb) && na !== nb) return na - nb
+  if (!Number.isNaN(na) && Number.isNaN(nb)) return -1
+  if (Number.isNaN(na) && !Number.isNaN(nb)) return 1
+  return String(a?.['工序'] ?? '').localeCompare(String(b?.['工序'] ?? ''), undefined, { numeric: true })
+}
+
+const compareUniqId = (a, b) => {
+  const ua = Number(a?.UniqId)
+  const ub = Number(b?.UniqId)
+  if (!Number.isNaN(ua) && !Number.isNaN(ub) && ua !== ub) return ua - ub
+  return String(a?.UniqId ?? '').localeCompare(String(b?.UniqId ?? ''), undefined, { numeric: true })
+}
+
+/** 列表展示:先按「工序」升序,再按 UniqId 升序 */
+const sortDeviceRows = (rows) => {
+  if (!Array.isArray(rows) || rows.length === 0) return []
+  return [...rows].sort((a, b) => {
+    const c = compareProcessField(a, b)
+    if (c !== 0) return c
+    return compareUniqId(a, b)
+  })
+}
+
+const minProcessInGx = (list, gxLabel) => {
+  let minNum = Infinity
+  let fallback = ''
+  for (const row of list) {
+    const gx = String(row['生产工序'] ?? '').trim() || '未分类'
+    if (gx !== gxLabel) continue
+    const n = Number(row['工序'])
+    if (!Number.isNaN(n) && n < minNum) minNum = n
+    if (fallback === '') fallback = String(row['工序'] ?? '')
+  }
+  return minNum !== Infinity ? minNum : fallback
+}
+
+const compareGxLabels = (list, a, b) => {
+  const pa = minProcessInGx(list, a)
+  const pb = minProcessInGx(list, b)
+  const na = Number(pa)
+  const nb = Number(pb)
+  if (!Number.isNaN(na) && !Number.isNaN(nb) && na !== nb) return na - nb
+  if (!Number.isNaN(na) && Number.isNaN(nb)) return -1
+  if (Number.isNaN(na) && !Number.isNaN(nb)) return 1
+  const s = String(pa).localeCompare(String(pb), undefined, { numeric: true })
+  if (s !== 0) return s
+  return a.localeCompare(b, 'zh-CN')
+}
+
+const minUniqInTeam = (list, gxLabel, team) => {
+  let min = Infinity
+  for (const row of list) {
+    const gx = String(row['生产工序'] ?? '').trim() || '未分类'
+    if (gx !== gxLabel || String(row['设备编组'] ?? '').trim() !== team) continue
+    const u = Number(row.UniqId)
+    if (!Number.isNaN(u) && u < min) min = u
+  }
+  return min === Infinity ? 0 : min
+}
+
+/**
+ * 先按「生产工序」归类,再按「设备编组」去重;树节点顺序与表格一致:工序从小到大,编组内按 UniqId
+ */
+const buildGroupTree = (list) => {
+  if (!Array.isArray(list) || list.length === 0) return []
+  const gxMap = new Map()
+  for (const row of list) {
+    const gx = String(row['生产工序'] ?? '').trim() || '未分类'
+    const team = String(row['设备编组'] ?? '').trim()
+    if (!gxMap.has(gx)) gxMap.set(gx, new Set())
+    if (team) gxMap.get(gx).add(team)
+  }
+  const gxKeys = Array.from(gxMap.keys()).sort((a, b) => compareGxLabels(list, a, b))
+  return gxKeys.map((gx) => {
+    const teams = Array.from(gxMap.get(gx)).sort((a, b) => {
+      const d = minUniqInTeam(list, gx, a) - minUniqInTeam(list, gx, b)
+      if (d !== 0) return d
+      return a.localeCompare(b, 'zh-CN')
+    })
+    return {
+      id: `gx-${gx}`,
+      label: gx,
+      children: teams.map((team) => ({
+        id: `team-${gx}::${team}`,
+        label: team,
+        meta: { 生产工序: gx, 设备编组: team },
+      })),
+    }
+  })
+}
+
+const loadData = async () => {
+  try {
+    const res = await getMachineDeviceTypes()
+    if (res?.code !== 0) {
+      ElMessage.error(res?.msg || '获取设备列表失败')
+      rawList.value = []
+      groupTreeData.value = []
+      return
+    }
+    const list = res?.data?.list ?? []
+    rawList.value = list
+    groupTreeData.value = buildGroupTree(list)
+    selectedFilter.value = null
+    await nextTick()
+    treeRef.value?.setCurrentKey(null)
+  } catch (e) {
+    console.error(e)
+    rawList.value = []
+    groupTreeData.value = []
+    ElMessage.error('获取设备列表失败')
+  }
+}
+
+const displayList = computed(() => {
+  const list = rawList.value
+  const f = selectedFilter.value
+  let filtered = list
+  if (f) {
+    const gx = f['生产工序']
+    const team = f['设备编组']
+    if (team) {
+      filtered = list.filter((r) => r['生产工序'] === gx && r['设备编组'] === team)
+    } else {
+      filtered = list.filter((r) => r['生产工序'] === gx)
+    }
+  }
+  return sortDeviceRows(filtered)
+})
+
+const filterHint = computed(() => {
+  const f = selectedFilter.value
+  if (!f) return '当前显示全部设备;点击左侧树可按工序或编组筛选'
+  if (f['设备编组']) {
+    return `筛选:${f['生产工序']} → ${f['设备编组']}`
+  }
+  return `筛选:生产工序「${f['生产工序']}」下全部设备`
+})
+
+const onTreeNodeClick = (data) => {
+  if (data.meta) {
+    selectedFilter.value = {
+      生产工序: data.meta['生产工序'],
+      设备编组: data.meta['设备编组'],
+    }
+    return
+  }
+  if (data.children?.length) {
+    selectedFilter.value = { 生产工序: data.label, 设备编组: '' }
+  }
+}
+
+const clearFilter = () => {
+  selectedFilter.value = null
+  treeRef.value?.setCurrentKey(null)
+}
+
+onMounted(() => {
+  loadData()
+})
+</script>
+
+<style scoped>
+.group-tree-wrap {
+  background: #fff;
+  padding: 10px;
+  min-height: 260px;
+  max-height: calc(100vh - 120px);
+  overflow: auto;
+}
+.group-tree-title {
+  font-size: 15px;
+  font-weight: 700;
+  margin: 0 0 10px;
+}
+.tree-node-text {
+  font-size: 13px;
+}
+.filter-row {
+  display: flex;
+  align-items: center;
+  gap: 12px;
+  margin-bottom: 10px;
+  flex-wrap: wrap;
+}
+.filter-hint {
+  font-size: 13px;
+  color: #606266;
+}
+.gva-pagination {
+  margin-top: 10px;
+}
+.total-text {
+  font-size: 13px;
+  color: #909399;
+}
+</style>

Plik diff jest za duży
+ 589 - 450
src/view/yunyin/renliziyuan/renyuanjibenziliao.vue


+ 6 - 4
src/view/yunyin/shengchanguanli/Orderprogress.vue

@@ -173,6 +173,7 @@ const userStore = useUserStore()
 const _username = ref('')
 _username.value = userStore.userInfo.userName + '/' + userStore.userInfo.nickName
 console.log('获取用户名称',_username.value)
+
 //全局调用获取当前日期
 const today = new Date();
 const year = today.getFullYear();
@@ -186,7 +187,7 @@ const currentDates = `${year}-${month}-${day}`;
 
 
 // 获取环境变量服务器IP地址
-const basePath = import.meta.env.VITE_BASE_PATH;
+const basePath = import.meta.env.VITE_BASE_PATH ?? 'http://192.168.28.22';
 const uploadsPort = import.meta.env.VITE_UPLOADS_PORT ?? '8082';
 console.log("basePath", basePath);
 console.log("uploadsPort", uploadsPort);
@@ -203,17 +204,18 @@ const formatImageUrl = (path) => {
   }
   // 否则拼接base路径
   const imagePath = path.replace(/^public\//, ''); // 移除可能的public前缀
-  return `${base}/${imagePath}`;
+ return `${basePath}:${uploadsPort}${imagePath}`;
+  // return `${base}/${imagePath}`;
 };
 
 // =========== 生产进度相关 =========== 
 const searchInfo = ref('');
 const page = ref(1);
-const pageSize = ref(30); // 默认每页显示5条,确保在一页内展示
+const pageSize = ref(30); // 默认每页显示X条
 const total = ref(0);
 const restableData = ref([]);
 const selectedOrder = ref(null); // 当前选中的订单数据
-
+          
 // 生产工序配置
 const processSteps = ref([
   { name: '裁剪', label: '裁剪', teamField: '裁剪小组' },

Niektóre pliki nie zostały wyświetlone z powodu dużej ilości zmienionych plików