iker 3 weeks ago
parent
commit
7cea7aa1fe

+ 377 - 0
1.html

@@ -0,0 +1,377 @@
+<template>
+  <div class="app-container">
+    <!-- 搜索栏 -->
+    <el-form :model="queryParams" inline class="search-form">
+      <el-form-item label="申请人">
+        <el-input
+          v-model="queryParams.applicant"
+          placeholder="请输入申请人"
+          clearable
+          @keyup.enter="handleSearch"
+        />
+      </el-form-item>
+      <el-form-item label="状态">
+        <el-select
+          v-model="queryParams.status"
+          placeholder="全部状态"
+          clearable
+        >
+          <el-option
+            v-for="item in statusOptions"
+            :key="item.value"
+            :label="item.label"
+            :value="item.value"
+          />
+        </el-select>
+      </el-form-item>
+      <el-form-item>
+        <el-button type="primary" @click="handleSearch">查询</el-button>
+        <el-button @click="resetQuery">重置</el-button>
+        <el-button
+          type="primary"
+          @click="handleCreate"
+          v-permission="'apply:create'"
+        >
+          新建申请
+        </el-button>
+      </el-form-item>
+    </el-form>
+
+    <!-- 数据表格 -->
+    <el-table
+      :data="tableData"
+      border
+      v-loading="loading"
+      element-loading-text="数据加载中..."
+    >
+      <el-table-column prop="applyNo" label="申请单号" width="180" fixed />
+      <el-table-column prop="applicant" label="申请人" width="120" />
+      <el-table-column prop="applyTime" label="申请时间" width="180" sortable />
+      <el-table-column prop="specimenName" label="标本名称" min-width="150" />
+      <el-table-column prop="specimenNo" label="标本编号" width="120" />
+      <el-table-column prop="purpose" label="用途" show-overflow-tooltip />
+      <el-table-column label="附件" width="120">
+        <template #default="{ row }">
+          <div v-if="row.attachments?.length">
+            <el-tooltip
+              v-for="(file, index) in row.attachments"
+              :key="index"
+              :content="file.name"
+            >
+              <el-link
+                type="primary"
+                :href="file.url"
+                target="_blank"
+                class="file-link"
+              >
+                <el-icon><Document /></el-icon>
+              </el-link>
+            </el-tooltip>
+          </div>
+          <span v-else>--</span>
+        </template>
+      </el-table-column>
+      <el-table-column prop="status" label="状态" width="100">
+        <template #default="{ row }">
+          <el-tag
+            :type="statusStyleMap[row.status]"
+            effect="light"
+          >
+            {{ statusMap[row.status] }}
+          </el-tag>
+        </template>
+      </el-table-column>
+      <el-table-column label="操作" width="150" fixed="right">
+        <template #default="{ row }">
+          <el-button
+            v-if="row.status === 0"
+            type="danger"
+            link
+            @click="handleWithdraw(row)"
+            v-permission="'apply:withdraw'"
+          >
+            撤回
+          </el-button>
+          <el-button
+            type="primary"
+            link
+            @click="handleDetail(row)"
+          >
+            详情
+          </el-button>
+        </template>
+      </el-table-column>
+    </el-table>
+
+    <!-- 分页 -->
+    <el-pagination
+      v-model:current-page="queryParams.pageNum"
+      v-model:page-size="queryParams.pageSize"
+      :total="total"
+      :page-sizes="[10, 20, 50, 100]"
+      layout="total, sizes, prev, pager, next, jumper"
+      @size-change="getList"
+      @current-change="getList"
+      class="pagination"
+    />
+
+    <!-- 申请弹窗 -->
+    <el-dialog
+      v-model="dialogVisible"
+      :title="dialogTitle"
+      width="600px"
+      :close-on-click-modal="false"
+    >
+      <el-form
+        ref="formRef"
+        :model="formData"
+        :rules="rules"
+        label-width="100px"
+        label-position="right"
+      >
+        <el-form-item label="标本选择" prop="specimenId">
+          <el-select
+            v-model="formData.specimenId"
+            placeholder="请选择标本"
+            filterable
+            remote
+            :remote-method="searchSpecimen"
+            :loading="specimenLoading"
+            style="width: 100%"
+          >
+            <el-option
+              v-for="item in specimenList"
+              :key="item.id"
+              :label="`${item.name} (${item.number})`"
+              :value="item.id"
+            />
+          </el-select>
+        </el-form-item>
+        <el-form-item label="用途说明" prop="purpose">
+          <el-input
+            v-model="formData.purpose"
+            type="textarea"
+            :rows="4"
+            placeholder="请输入详细的用途说明"
+            show-word-limit
+            maxlength="500"
+          />
+        </el-form-item>
+        <el-form-item label="附件">
+          <el-upload
+            v-model:file-list="fileList"
+            action="/api/upload"
+            multiple
+            :limit="3"
+            :on-exceed="handleExceed"
+            :before-upload="beforeUpload"
+            :on-success="handleUploadSuccess"
+            :on-error="handleUploadError"
+            list-type="text"
+          >
+            <el-button type="primary">选择文件</el-button>
+            <template #tip>
+              <div class="upload-tip">
+                支持格式:PDF/DOC/DOCX/图片,单个文件不超过10MB
+              </div>
+            </template>
+          </el-upload>
+        </el-form-item>
+      </el-form>
+      <template #footer>
+        <el-button @click="dialogVisible = false">取消</el-button>
+        <el-button
+          type="primary"
+          @click="submitForm"
+          :loading="submitting"
+        >
+          {{ submitting ? '提交中...' : '确认提交' }}
+        </el-button>
+      </template>
+    </el-dialog>
+  </div>
+</template>
+
+<script setup>
+import { ref, reactive, onMounted } from 'vue'
+import { ElMessage, ElMessageBox } from 'element-plus'
+import { Document } from '@element-plus/icons-vue'
+
+// 状态字典
+const statusMap = {
+  0: '待审核',
+  1: '已通过',
+  2: '已驳回',
+  3: '已撤回'
+}
+
+const statusStyleMap = {
+  0: 'warning',
+  1: 'success',
+  2: 'danger',
+  3: 'info'
+}
+
+const statusOptions = [
+  { label: '全部', value: '' },
+  { label: '待审核', value: 0 },
+  { label: '已通过', value: 1 },
+  { label: '已驳回', value: 2 },
+  { label: '已撤回', value: 3 }
+]
+
+// 数据加载状态
+const loading = ref(false)
+const submitting = ref(false)
+const specimenLoading = ref(false)
+
+// 表格数据
+const tableData = ref([])
+const total = ref(0)
+
+// 查询参数
+const queryParams = reactive({
+  pageNum: 1,
+  pageSize: 10,
+  applicant: '',
+  status: ''
+})
+
+// 表单数据
+const formData = reactive({
+  specimenId: '',
+  purpose: '',
+  attachments: []
+})
+
+// 标本列表
+const specimenList = ref([])
+
+// 文件列表
+const fileList = ref([])
+
+// 表单验证规则
+const rules = {
+  specimenId: [
+    { required: true, message: '请选择标本', trigger: 'blur' }
+  ],
+  purpose: [
+    { required: true, message: '请输入用途说明', trigger: 'blur' },
+    { min: 10, message: '至少输入10个字符', trigger: 'blur' }
+  ]
+}
+
+// 初始化加载
+onMounted(() => {
+  getList()
+  loadSpecimenList()
+})
+
+// 获取申请列表
+const getList = async () => {
+  try {
+    loading.value = true
+    // 调用API接口
+    const res = await fetchApplications(queryParams)
+    tableData.value = res.data.list
+    total.value = res.data.total
+  } catch (error) {
+    ElMessage.error('数据加载失败')
+  } finally {
+    loading.value = false
+  }
+}
+
+// 搜索标本
+const searchSpecimen = async (query) => {
+  if (!query) return
+  try {
+    specimenLoading.value = true
+    const res = await searchSpecimens({ keyword: query })
+    specimenList.value = res.data
+  } finally {
+    specimenLoading.value = false
+  }
+}
+
+// 提交表单
+const submitForm = async () => {
+  try {
+    await formRef.value.validate()
+    submitting.value = true
+    // 处理附件
+    const attachments = fileList.value.map(file => ({
+      name: file.name,
+      url: file.response?.data.url || ''
+    }))
+
+    await createApplication({
+      ...formData,
+      attachments
+    })
+
+    ElMessage.success('提交成功')
+    dialogVisible.value = false
+    getList()
+  } catch (error) {
+    console.error('提交失败:', error)
+  } finally {
+    submitting.value = false
+  }
+}
+
+// 撤回申请
+const handleWithdraw = async (row) => {
+  try {
+    await ElMessageBox.confirm('确定要撤回该申请吗?', '提示', {
+      type: 'warning'
+    })
+
+    await withdrawApplication(row.id)
+    ElMessage.success('已撤回申请')
+    getList()
+  } catch (error) {
+    if (error !== 'cancel') {
+      ElMessage.error('撤回失败')
+    }
+  }
+}
+
+// 文件上传处理
+const beforeUpload = (file) => {
+  const isAllowed = ['image/png', 'application/pdf', 'application/msword', 'application/vnd.openxmlformats-officedocument.wordprocessingml.document']
+    .includes(file.type)
+  const isLt10M = file.size / 1024 / 1024 < 10
+
+  if (!isAllowed) {
+    ElMessage.error('不支持的文件格式!')
+    return false
+  }
+  if (!isLt10M) {
+    ElMessage.error('文件大小不能超过10MB!')
+    return false
+  }
+  return true
+}
+</script>
+
+<style scoped>
+.search-form {
+  margin-bottom: 20px;
+}
+
+.file-link {
+  margin-right: 8px;
+}
+
+.upload-tip {
+  color: #666;
+  font-size: 12px;
+  margin-top: 8px;
+}
+
+.pagination {
+  margin-top: 20px;
+  justify-content: flex-end;
+}
+</style>

+ 0 - 0
src/api/system/Inner/index.ts


+ 76 - 0
src/api/system/Out/index.ts

@@ -0,0 +1,76 @@
+import request from '@/config/axios'
+
+export interface OouBoundVO {
+  id :number;
+  number:string;
+  sampleName: string;
+  outboundPerson :string;
+  outboundTime:Date;
+  purpose :string;
+  annexOut:string;
+  applyPerson:string;
+  applyUnit:string;
+  applyTime:Date;
+  returnExpect:string;
+  reviewPerson:string;
+  reviewTime: LocalDateTime;
+  rejectSeason:string;
+  returnPerson:string;
+  returnTime:LocalDateTime;
+  receivePerson:string;
+  annexReturn:string;
+  nots:string;
+  state:Integer;
+}
+
+export interface UpdateStatusReqVO {
+  id: number
+  status: number
+}
+
+export const getPage = (params) => {
+  return request.get({ url: '/museum/flow/pagePerson', params })
+}
+
+// 查询角色列表
+export const getRolePage = async (params: PageParam) => {
+  return await request.get({ url: '/system/Out/page', params })
+}
+
+// 查询角色(精简)列表
+export const getSimpleRoleList = async (): Promise<RoleVO[]> => {
+  return await request.get({ url: '/system/role/simple-list' })
+}
+
+// 查询角色详情
+export const getRole = async (id: number) => {
+  return await request.get({ url: '/system/Out/get?id=' + id })
+}
+
+// 新增出库表单
+export const createOutBound = async (data) => {
+  return await request.post({ url: '/museum/flow/outbound', data })
+}
+
+// 跟新表单
+export const updateForm = async (data) => {
+  return await request.put({ url: '/museum/flow/update', data })
+}
+
+// 修改角色状态
+export const updateRoleStatus = async (data: UpdateStatusReqVO) => {
+  return await request.put({ url: '/system/Out/update-status', data })
+}
+
+// 删除角色
+export const deleteRole = async (id: number) => {
+  return await request.delete({ url: '/system/Out/delete?id=' + id })
+}
+
+// 导出角色
+export const exportRole = (params) => {
+  return request.download({
+    url: '/system/Out/export-excel',
+    params
+  })
+}

+ 122 - 0
src/views/system/Inner/1.vue

@@ -0,0 +1,122 @@
+<template>
+  <div class="app-container">
+    <!-- 搜索栏 -->
+    <el-form :model="queryParams" inline>
+      <el-form-item label="名称">
+        <el-input v-model="queryParams.name" placeholder="标本名称" clearable />
+      </el-form-item>
+      <el-form-item label="编号">
+        <el-input v-model="queryParams.number" placeholder="标本编号" clearable />
+      </el-form-item>
+      <el-form-item>
+        <el-button type="primary" @click="handleSearch">搜索</el-button>
+        <el-button @click="resetQuery">重置</el-button>
+        <el-button type="primary" @click="handleExport">导出</el-button>
+      </el-form-item>
+    </el-form>
+
+    <!-- 数据表格 -->
+    <el-table :data="tableData" border>
+      <el-table-column prop="number" label="编号" width="120" />
+      <el-table-column prop="name" label="名称" width="150" />
+      <el-table-column prop="location" label="存放位置" />
+      <el-table-column label="图片" width="100">
+        <template #default="{ row }">
+          <el-image :src="row.image" style="width: 50px; height: 50px" />
+        </template>
+      </el-table-column>
+      <el-table-column prop="returnBy" label="退还人" width="120" />
+      <el-table-column prop="returnTime" label="退还时间" width="180" />
+      <el-table-column prop="receiver" label="点收人" width="120" />
+      <el-table-column prop="status" label="回库状态" width="100">
+        <template #default="{ row }">
+          <el-tag :type="row.status === '已回库' ? 'success' : 'warning'">
+            {{ row.status }}
+          </el-tag>
+        </template>
+      </el-table-column>
+      <el-table-column label="操作" width="220" fixed="right">
+        <template #default="{ row }">
+          <el-button type="primary" link @click="handleConfirm(row)">确认回库</el-button>
+          <el-button type="primary" link @click="handleEdit(row)">编辑</el-button>
+          <el-button type="danger" link @click="handleDelete(row)">删除</el-button>
+        </template>
+      </el-table-column>
+    </el-table>
+
+    <!-- 分页 -->
+    <el-pagination
+      v-model:current-page="queryParams.pageNum"
+      v-model:page-size="queryParams.pageSize"
+      :total="total"
+      layout="total, sizes, prev, pager, next, jumper"
+      @size-change="getList"
+      @current-change="getList"
+    />
+
+    <!-- 编辑弹窗 -->
+    <el-dialog v-model="dialogVisible" title="入库记录编辑">
+      <el-form ref="formRef" :model="form" :rules="rules" label-width="100px">
+        <el-form-item label="退还人" prop="returnBy">
+          <el-input v-model="form.returnBy" placeholder="请输入退还人姓名" />
+        </el-form-item>
+        <el-form-item label="点收人" prop="receiver">
+          <el-input v-model="form.receiver" placeholder="请输入点收人姓名" />
+        </el-form-item>
+        <el-form-item label="退还时间" prop="returnTime">
+          <el-date-picker
+            v-model="form.returnTime"
+            type="datetime"
+            placeholder="选择日期时间"
+          />
+        </el-form-item>
+        <el-form-item label="备注">
+          <el-input v-model="form.note" type="textarea" :rows="3" />
+        </el-form-item>
+      </el-form>
+      <template #footer>
+        <el-button @click="dialogVisible = false">取消</el-button>
+        <el-button type="primary" @click="submitForm">保存</el-button>
+      </template>
+    </el-dialog>
+  </div>
+</template>
+
+<script setup>
+import { ref, reactive } from 'vue'
+
+const tableData = ref([
+  {
+    id: 1,
+    number: 'RT-001',
+    name: '矿石标本',
+    location: 'B区-3柜',
+    image: 'https://via.placeholder.com/50',
+    returnBy: '张三',
+    returnTime: '2024-03-01 14:30:00',
+    receiver: '李四',
+    status: '已入库',
+    note: '包装完好'
+  }
+])
+
+const queryParams = reactive({
+  pageNum: 1,
+  pageSize: 10,
+  name: '',
+  number: ''
+})
+
+const form = reactive({
+  id: null,
+  returnBy: '',
+  receiver: '',
+  returnTime: '',
+  note: ''
+})
+
+const rules = {
+  returnBy: [{ required: true, message: '退还人不能为空', trigger: 'blur' }],
+  receiver: [{ required: true, message: '点收人不能为空', trigger: 'blur' }]
+}
+</script>

+ 126 - 0
src/views/system/Inner/InnerForm.vue

@@ -0,0 +1,126 @@
+<template>
+  <Dialog v-model="dialogVisible" :title="dialogTitle">
+    <el-form
+      ref="formRef"
+      v-loading="formLoading"
+      :model="formData"
+      :rules="formRules"
+      label-width="80px"
+    >
+      <el-form-item label="角色名称" prop="name">
+        <el-input v-model="formData.name" placeholder="请输入角色名称" />
+      </el-form-item>
+      <el-form-item label="角色标识" prop="code">
+        <el-input v-model="formData.code" placeholder="请输入角色标识" />
+      </el-form-item>
+      <el-form-item label="显示顺序" prop="sort">
+        <el-input v-model="formData.sort" placeholder="请输入显示顺序" />
+      </el-form-item>
+      <el-form-item label="状态" prop="status">
+        <el-select v-model="formData.status" clearable placeholder="请选择状态">
+          <el-option
+            v-for="dict in getIntDictOptions(DICT_TYPE.COMMON_STATUS)"
+            :key="dict.value"
+            :label="dict.label"
+            :value="dict.value"
+          />
+        </el-select>
+      </el-form-item>
+      <el-form-item label="备注" prop="remark">
+        <el-input v-model="formData.remark" placeholder="请输备注" type="textarea" />
+      </el-form-item>
+    </el-form>
+    <template #footer>
+      <el-button :disabled="formLoading" type="primary" @click="submitForm">确 定</el-button>
+      <el-button @click="dialogVisible = false">取 消</el-button>
+    </template>
+  </Dialog>
+</template>
+<script lang="ts" setup>
+import { DICT_TYPE, getIntDictOptions } from '@/utils/dict'
+import { CommonStatusEnum } from '@/utils/constants'
+import * as RoleApi from '@/api/system/role'
+
+defineOptions({ name: 'SystemRoleForm' })
+
+const { t } = useI18n() // 国际化
+const message = useMessage() // 消息弹窗
+
+const dialogVisible = ref(false) // 弹窗的是否展示
+const dialogTitle = ref('') // 弹窗的标题
+const formLoading = ref(false) // 表单的加载中:1)修改时的数据加载;2)提交的按钮禁用
+const formType = ref('') // 表单的类型:create - 新增;update - 修改
+const formData = ref({
+  id: undefined,
+  name: '',
+  code: '',
+  sort: undefined,
+  status: CommonStatusEnum.ENABLE,
+  remark: ''
+})
+const formRules = reactive({
+  name: [{ required: true, message: '角色名称不能为空', trigger: 'blur' }],
+  code: [{ required: true, message: '角色标识不能为空', trigger: 'change' }],
+  sort: [{ required: true, message: '显示顺序不能为空', trigger: 'change' }],
+  status: [{ required: true, message: '状态不能为空', trigger: 'change' }],
+  remark: [{ required: false, message: '备注不能为空', trigger: 'blur' }]
+})
+const formRef = ref() // 表单 Ref
+
+/** 打开弹窗 */
+const open = async (type: string, id?: number) => {
+  dialogVisible.value = true
+  dialogTitle.value = t('action.' + type)
+  formType.value = type
+  resetForm()
+  // 修改时,设置数据
+  if (id) {
+    formLoading.value = true
+    try {
+      formData.value = await RoleApi.getRole(id)
+    } finally {
+      formLoading.value = false
+    }
+  }
+}
+
+/** 重置表单 */
+const resetForm = () => {
+  formData.value = {
+    id: undefined,
+    name: '',
+    code: '',
+    sort: undefined,
+    status: CommonStatusEnum.ENABLE,
+    remark: ''
+  }
+  formRef.value?.resetFields()
+}
+defineExpose({ open }) // 提供 open 方法,用于打开弹窗
+
+/** 提交表单 */
+const emit = defineEmits(['success']) // 定义 success 事件,用于操作成功后的回调
+const submitForm = async () => {
+  // 校验表单
+  if (!formRef) return
+  const valid = await formRef.value.validate()
+  if (!valid) return
+  // 提交请求
+  formLoading.value = true
+  try {
+    const data = formData.value as unknown as RoleApi.RoleVO
+    if (formType.value === 'create') {
+      await RoleApi.createRole(data)
+      message.success(t('common.createSuccess'))
+    } else {
+      await RoleApi.updateRole(data)
+      message.success(t('common.updateSuccess'))
+    }
+    dialogVisible.value = false
+    // 发送操作成功的事件
+    emit('success')
+  } finally {
+    formLoading.value = false
+  }
+}
+</script>

+ 289 - 328
src/views/system/Inner/iker.vue

@@ -1,354 +1,315 @@
 <template>
 <template>
-  <div class="in-request-page">
-    <h1>标本入库申请</h1>
-
-    <!-- 搜索栏 -->
-    <div class="search-bar">
-      <input v-model="searchForm.name" placeholder="名称" />
-      <input v-model="searchForm.number" placeholder="编号" />
-      <button @click="search">搜索</button>
-      <button @click="resetSearch">重置</button>
-      <button @click="exportData">导出</button>
-    </div>
-
-    <!-- 数据表格 -->
-    <table class="data-table">
-      <thead>
-      <tr>
-        <th>编号</th>
-        <th>名称</th>
-        <th>存放位置</th>
-        <th>图片</th>
-        <th>退还人</th>
-        <th>退还时间</th>
-        <th>点收人</th>
-        <th>回库状态</th>
-        <th>操作</th>
-      </tr>
-      </thead>
-      <tbody>
-      <tr v-for="item in filteredData" :key="item.id">
-        <td>{{ item.number }}</td>
-        <td>{{ item.name }}</td>
-        <td>{{ item.location }}</td>
-        <td>
-          <img :src="item.image" alt="标本图片" class="specimen-image" />
-        </td>
-        <td>{{ item.returner }}</td>
-        <td>{{ item.returnTime }}</td>
-        <td>{{ item.receiver }}</td>
-        <td>
-          <span :class="`status ${item.status}`">{{ item.status }}</span>
-        </td>
-        <td>
-          <button @click="confirmReturn(item.id)">确认回库</button>
-          <button @click="editItem(item)">编辑</button>
-          <button @click="deleteItem(item.id)">删除</button>
-        </td>
-      </tr>
-      </tbody>
-    </table>
-
-    <!-- 入库申请弹窗 -->
-    <div v-if="showModal" class="modal">
-      <div class="modal-content">
-        <h2>入库申请表单</h2>
-        <div>
-          <label>申请人:</label>
-          <input v-model="requestForm.applicant" placeholder="申请人" />
-        </div>
-        <div>
-          <label>申请时间:</label>
-          <input v-model="requestForm.applyTime" type="date" />
-        </div>
-        <div>
-          <label>标本名称:</label>
-          <input v-model="requestForm.specimenName" placeholder="标本名称" />
-        </div>
-        <div>
-          <label>标本编号:</label>
-          <input v-model="requestForm.specimenNumber" placeholder="标本编号" />
-        </div>
-        <div>
-          <label>用途:</label>
-          <input v-model="requestForm.purpose" placeholder="用途" />
-        </div>
-        <div>
-          <label>附件:</label>
-          <input type="file" @change="handleFileUpload" />
-        </div>
-        <div>
-          <button @click="submitRequest">提交</button>
-          <button @click="closeModal">取消</button>
-        </div>
-      </div>
-    </div>
-
-    <!-- 提交申请按钮 -->
-    <button class="submit-button" @click="openRequestModal">提交入库申请</button>
-  </div>
+  <ContentWrap>
+  <!-- 搜索栏 -->
+<el-form
+  class="-mb-15px"
+  :model="queryParams"
+  ref="queryFormRef"
+  :inline="true"
+  label-width="68px"
+>
+  <el-form-item label="名称" prop="name">
+    <el-input
+      v-model="queryParams.name"
+      placeholder="请输入名称"
+      clearable
+      @keyup.enter="handleQuery"
+      class="!w-240px"
+    />
+  </el-form-item>
+  <el-form-item label="编号" prop="number">
+    <el-input
+      v-model="queryParams.number"
+      placeholder="请输入手机号码"
+      clearable
+      @keyup.enter="handleQuery"
+      class="!w-240px"
+    />
+  </el-form-item>
+  <el-form-item>
+    <el-button @click="handleQuery"><Icon icon="ep:search" />搜索</el-button>
+    <el-button @click="resetQuery"><Icon icon="ep:refresh" />重置</el-button>
+                <el-button
+                  type="primary"
+                  plain
+                  @click="openForm('create')"
+                >
+                  <Icon icon="ep:plus" /> 新增
+                </el-button>
+                <el-button
+                  type="warning"
+                  plain
+                  @click="handleImport"
+                >
+                  <Icon icon="ep:upload" /> 导入
+                </el-button>
+                <el-button
+                  type="success"
+                  plain
+                  @click="handleExport"
+                  :loading="exportLoading"
+                >
+                  <Icon icon="ep:download" />导出
+                </el-button>
+  </el-form-item>
+</el-form>
+</contentwrap>
+<!-- 数据表格 -->
+<ContentWrap>
+<el-table v-loading="loading" :data="list">
+  <el-table-column label="编号" align="center" prop="number" />
+  <el-table-column
+    label="名称"
+    align="center"
+    prop="name"
+    :show-overflow-tooltip="true"
+  />
+  <el-table-column
+    label="存放位置"
+    align="center"
+    prop="location"
+    :show-overflow-tooltip="true"
+  />
+  <el-table-column
+    label="图片"
+    align="center"
+    prop="image"
+    :show-overflow-tooltip="true"
+  />
+  <el-table-column label="退还人" align="center" prop="returner" width="120" />
+  <el-table-column
+    :formatter="dateFormatter"
+    label="退还时间"
+    prop="returnTime"
+  />
+  <el-table-column
+    label="点收人"
+    align="center"
+    prop="receiver"
+    width="180"
+  />
+  <el-table-column
+    label="回库状态"
+    align="center"
+    prop="status"
+    :show-overflow-tooltip="true"
+  />
+  <!--          <el-table-column label="操作" align="center" width="160">-->
+  <!--            <template #default="scope">-->
+  <!--              <div class="flex items-center justify-center">-->
+  <!--                <el-button-->
+  <!--                  type="primary"-->
+  <!--                  link-->
+  <!--                  @click="openForm('update', scope.row.id)"-->
+  <!--                  v-hasPermi="['system:user:update']"-->
+  <!--                >-->
+  <!--                  <Icon icon="ep:edit" />修改-->
+  <!--                </el-button>-->
+  <!--                <el-dropdown-->
+  <!--                  @command="(command) => handleCommand(command, scope.row)"-->
+  <!--                  v-hasPermi="[-->
+  <!--                    'system:user:delete',-->
+  <!--                    'system:user:update-password',-->
+  <!--                    'system:permission:assign-user-role'-->
+  <!--                  ]"-->
+  <!--                >-->
+  <!--                  <el-button type="primary" link><Icon icon="ep:d-arrow-right" /> 更多</el-button>-->
+  <!--                  <template #dropdown>-->
+  <!--                    <el-dropdown-menu>-->
+  <!--                      <el-dropdown-item-->
+  <!--                        command="handleDelete"-->
+  <!--                        v-if="checkPermi(['system:user:delete'])"-->
+  <!--                      >-->
+  <!--                        <Icon icon="ep:delete" />删除-->
+  <!--                      </el-dropdown-item>-->
+  <!--                      <el-dropdown-item-->
+  <!--                        command="handleResetPwd"-->
+  <!--                        v-if="checkPermi(['system:user:update-password'])"-->
+  <!--                      >-->
+  <!--                        <Icon icon="ep:key" />重置密码-->
+  <!--                      </el-dropdown-item>-->
+  <!--                      <el-dropdown-item-->
+  <!--                        command="handleRole"-->
+  <!--                        v-if="checkPermi(['system:permission:assign-user-role'])"-->
+  <!--                      >-->
+  <!--                        <Icon icon="ep:circle-check" />分配角色-->
+  <!--                      </el-dropdown-item>-->
+  <!--                    </el-dropdown-menu>-->
+  <!--                  </template>-->
+  <!--                </el-dropdown>-->
+  <!--              </div>-->
+  <!--            </template>-->
+  <!--          </el-table-column>-->
+          </el-table>
+  <!--        <Pagination-->
+  <!--          :total="total"-->
+  <!--          v-model:page="queryParams.pageNo"-->
+  <!--          v-model:limit="queryParams.pageSize"-->
+  <!--          @pagination="getList"-->
+  <!--        />-->
+</ContentWrap>
+<!--  &lt;!&ndash; 添加或修改用户对话框 &ndash;&gt;-->
+<!--  <UserForm ref="formRef" @success="getList" />-->
+<!--  &lt;!&ndash; 用户导入对话框 &ndash;&gt;-->
+<!--  <UserImportForm ref="importFormRef" @success="getList" />-->
+<!--  &lt;!&ndash; 分配角色 &ndash;&gt;-->
+<!--  <UserAssignRoleForm ref="assignRoleFormRef" @success="getList" />-->
 </template>
 </template>
-
-<script>
-import { ref, computed } from 'vue';
-
-export default {
-  name: 'InRequest',
-  setup() {
-    // 搜索表单
-    const searchForm = ref({
-      name: '',
-      number: '',
-    });
-
-    // 入库申请表单
-    const showModal = ref(false);
-    const requestForm = ref({
-      applicant: '',
-      applyTime: '',
-      specimenName: '',
-      specimenNumber: '',
-      purpose: '',
-      attachment: null,
-    });
-
-    // 数据列表
-    const data = ref([
-      {
-        id: 1,
-        number: 'RT-001 系列',
-        name: '矿石标本',
-        location: 'B区-3柜',
-        image: 'https://via.placeholder.com/50', // 替换为实际图片链接
-        returner: '张三',
-        returnTime: '2024-03-01 14:30:00',
-        receiver: '李四',
-        status: '已入库',
-      },
-      {
-        id: 2,
-        number: 'RT-002 系列',
-        name: '矿石标本',
-        location: 'B区-4柜',
-        image: 'https://via.placeholder.com/50', // 替换为实际图片链接
-        returner: '王五',
-        returnTime: '2024-03-02 15:45:00',
-        receiver: '赵六',
-        status: '待审核',
-      },
-    ]);
-
-    // 过滤数据
-    const filteredData = computed(() => {
-      return data.value.filter((item) =>
-        `${item.name}${item.number}`.includes(`${searchForm.value.name}${searchForm.value.number}`)
-      );
-    });
-
-    // 搜索
-    const search = () => {
-      console.log('搜索中...');
-    };
-
-    // 重置搜索
-    const resetSearch = () => {
-      searchForm.value = { name: '', number: '' };
-    };
-
-    // 导出数据
-    const exportData = () => {
-      console.log('导出数据...');
-    };
-
-    // 打开入库申请弹窗
-    const openRequestModal = () => {
-      showModal.value = true;
-    };
-
-    // 关闭弹窗
-    const closeModal = () => {
-      showModal.value = false;
-      requestForm.value = {
-        applicant: '',
-        applyTime: '',
-        specimenName: '',
-        specimenNumber: '',
-        purpose: '',
-        attachment: null,
-      };
-    };
-
-    // 提交入库申请
-    const submitRequest = () => {
-      const newRequest = {
-        id: data.value.length + 1,
-        ...requestForm.value,
-        status: '待审核',
-      };
-      data.value.push(newRequest);
-      closeModal();
-    };
-
-    // 确认回库
-    const confirmReturn = (id) => {
-      const index = data.value.findIndex((item) => item.id === id);
-      if (index !== -1) {
-        data.value[index].status = '已入库';
-      }
-    };
-
-    // 编辑数据
-    const editItem = (item) => {
-      console.log('编辑', item);
-    };
-
-    // 删除数据
-    const deleteItem = (id) => {
-      data.value = data.value.filter((item) => item.id !== id);
-    };
-
-    // 文件上传
-    const handleFileUpload = (event) => {
-      const file = event.target.files[0];
-      if (file) {
-        requestForm.value.attachment = URL.createObjectURL(file);
-      }
-    };
-
-    return {
-      searchForm,
-      showModal,
-      requestForm,
-      data,
-      filteredData,
-      search,
-      resetSearch,
-      exportData,
-      openRequestModal,
-      closeModal,
-      submitRequest,
-      confirmReturn,
-      editItem,
-      deleteItem,
-      handleFileUpload,
-    };
-  },
-};
-</script>
-
-<style scoped>
-.in-request-page {
-  padding: 20px;
-  background-color: #f9f9f9;
-  border-radius: 8px;
-  box-shadow: 0 2px 4px rgba(0, 0, 0, 0.1);
-}
-
-.search-bar {
-  margin-bottom: 20px;
-  display: flex;
-  gap: 10px;
-}
-
-.search-bar input {
-  padding: 8px;
-  border: 1px solid #ccc;
-  border-radius: 4px;
-  flex: 1;
+<script lang="ts" setup>
+import { DICT_TYPE, getIntDictOptions } from '@/utils/dict'
+import { checkPermi } from '@/utils/permission'
+import { dateFormatter } from '@/utils/formatTime'
+import download from '@/utils/download'
+import { CommonStatusEnum } from '@/utils/constants'
+// import * as UserApi from '@/api/system/user'
+
+defineOptions({ name: 'SystemUser' })
+
+const message = useMessage() // 消息弹窗
+const { t } = useI18n() // 国际化
+
+const loading = ref(true) // 列表的加载中
+const total = ref(0) // 列表的总页数
+const list = ref() // 列表的数
+const queryParams = reactive({
+  pageNo: 1,
+  pageSize: 10,
+  number: undefined,
+  name: undefined,
+  // status: undefined,
+  // deptId: undefined,
+  // createTime: []
+})
+const queryFormRef = ref() // 搜索的表单
+
+/** 查询列表 */
+const getList = async () => {
+  loading.value = true
+  try {
+    const data = []
+    list.value = data.list
+    // total.value = data.total
+  } finally {
+    loading.value = false
+  }
 }
 }
 
 
-.search-bar button {
-  padding: 8px 16px;
-  background-color: #007bff;
-  color: white;
-  border: none;
-  border-radius: 4px;
-  cursor: pointer;
+/** 搜索按钮操作 */
+const handleQuery = () => {
+  queryParams.pageNo = 1
+  getList()
 }
 }
 
 
-.data-table {
-  width: 100%;
-  border-collapse: collapse;
-  margin-bottom: 20px;
+/** 重置按钮操作 */
+const resetQuery = () => {
+  queryFormRef.value?.resetFields()
+  handleQuery()
 }
 }
 
 
-.data-table th,
-.data-table td {
-  border: 1px solid #ddd;
-  padding: 12px;
-  text-align: left;
+/** 处理部门被点击 */
+const handleDeptNodeClick = async (row) => {
+  queryParams.deptId = row.id
+  await getList()
 }
 }
 
 
-.data-table th {
-  background-color: #f2f2f2;
+/** 添加/修改操作 */
+const formRef = ref()
+const openForm = (type: string, id?: number) => {
+  formRef.value.open(type, id)
 }
 }
 
 
-.status {
-  padding: 4px 8px;
-  border-radius: 4px;
-  font-size: 12px;
-  color: white;
+/** 用户导入 */
+const importFormRef = ref()
+const handleImport = () => {
+  importFormRef.value.open()
 }
 }
 
 
-.status.已入库 {
-  background-color: #4caf50;
+/** 修改用户状态 */
+const handleStatusChange = async (row: UserApi.UserVO) => {
+  try {
+    // 修改状态的二次确认
+    const text = row.status === CommonStatusEnum.ENABLE ? '启用' : '停用'
+    await message.confirm('确认要"' + text + '""' + row.username + '"用户吗?')
+    // 发起修改状态
+    await UserApi.updateUserStatus(row.id, row.status)
+    // 刷新列表
+    await getList()
+  } catch {
+    // 取消后,进行恢复按钮
+    row.status =
+      row.status === CommonStatusEnum.ENABLE ? CommonStatusEnum.DISABLE : CommonStatusEnum.ENABLE
+  }
 }
 }
 
 
-.status.待审核 {
-  background-color: #ff9800;
+/** 导出按钮操作 */
+const exportLoading = ref(false)
+const handleExport = async () => {
+  try {
+    // 导出的二次确认
+    await message.exportConfirm()
+    // 发起导出
+    exportLoading.value = true
+    const data = await UserApi.exportUser(queryParams)
+    download.excel(data, '用户数据.xls')
+  } catch {
+  } finally {
+    exportLoading.value = false
+  }
 }
 }
 
 
-.specimen-image {
-  width: 50px;
-  height: 50px;
-  object-fit: cover;
+/** 操作分发 */
+const handleCommand = (command: string, row: UserApi.UserVO) => {
+  switch (command) {
+    case 'handleDelete':
+      handleDelete(row.id)
+      break
+    case 'handleResetPwd':
+      handleResetPwd(row)
+      break
+    case 'handleRole':
+      handleRole(row)
+      break
+    default:
+      break
+  }
 }
 }
 
 
-.modal {
-  position: fixed;
-  top: 0;
-  left: 0;
-  width: 100%;
-  height: 100%;
-  background: rgba(0, 0, 0, 0.5);
-  display: flex;
-  justify-content: center;
-  align-items: center;
+/** 删除按钮操作 */
+const handleDelete = async (id: number) => {
+  try {
+    // 删除的二次确认
+    await message.delConfirm()
+    // 发起删除
+    await UserApi.deleteUser(id)
+    message.success(t('common.delSuccess'))
+    // 刷新列表
+    await getList()
+  } catch {}
 }
 }
 
 
-.modal-content {
-  background: white;
-  padding: 20px;
-  border-radius: 8px;
-  width: 400px;
+/** 重置密码 */
+const handleResetPwd = async (row: UserApi.UserVO) => {
+  try {
+    // 重置的二次确认
+    const result = await message.prompt(
+      '请输入"' + row.username + '"的新密码',
+      t('common.reminder')
+    )
+    const password = result.value
+    // 发起重置
+    await UserApi.resetUserPwd(row.id, password)
+    message.success('修改成功,新密码是:' + password)
+  } catch {}
 }
 }
 
 
-.modal-content div {
-  margin-bottom: 10px;
+/** 分配角色 */
+const assignRoleFormRef = ref()
+const handleRole = (row: UserApi.UserVO) => {
+  assignRoleFormRef.value.open(row)
 }
 }
 
 
-.modal-content label {
-  display: block;
-  margin-bottom: 5px;
-}
-
-.modal-content input {
-  width: 100%;
-  padding: 8px;
-  box-sizing: border-box;
-}
-
-.modal-content button {
-  margin-right: 10px;
-}
-
-.submit-button {
-  padding: 10px 20px;
-  background-color: #007bff;
-  color: white;
-  border: none;
-  border-radius: 4px;
-  cursor: pointer;
-  margin-top: 20px;
-}
-</style>
+/** 初始化 */
+// onMounted(() => {
+//   getList()
+// })
+</script>

+ 238 - 95
src/views/system/Inner/index.vue

@@ -1,122 +1,265 @@
 <template>
 <template>
-  <div class="app-container">
-    <!-- 搜索栏 -->
-    <el-form :model="queryParams" inline>
-      <el-form-item label="名称">
-        <el-input v-model="queryParams.name" placeholder="标本名称" clearable />
+  <ContentWrap>
+    <!-- 搜索工具栏 -->
+    <el-form
+      ref="queryFormRef"
+      :inline="true"
+      :model="queryParams"
+      class="-mb-15px"
+      label-width="68px"
+    >
+      <el-form-item label="标本编号" prop="code">
+        <el-input
+          v-model="queryParams.code"
+          class="!w-240px"
+          clearable
+          placeholder="请输入标本编号"
+          @keyup.enter="handleQuery"
+        />
       </el-form-item>
       </el-form-item>
-      <el-form-item label="编号">
-        <el-input v-model="queryParams.number" placeholder="标本编号" clearable />
+      <el-form-item label="标本状态" prop="status">
+        <el-select
+          v-model="queryParams.status"
+          class="!w-240px"
+          clearable
+          placeholder="请选择标本状态"
+        >
+<!--          <el-option-->
+<!--            v-for="dict in getIntDictOptions(DICT_TYPE.COMMON_STATUS)"-->
+<!--            :key="dict.value"-->
+<!--            :label="dict.label"-->
+<!--            :value="dict.value"-->
+<!--          />-->
+        </el-select>
+      </el-form-item>
+      <el-form-item label="创建时间" prop="createTime">
+        <el-date-picker
+          v-model="queryParams.createTime"
+          :default-time="[new Date('1 00:00:00'), new Date('1 23:59:59')]"
+          class="!w-240px"
+          end-placeholder="结束日期"
+          start-placeholder="开始日期"
+          type="daterange"
+          value-format="YYYY-MM-DD HH:mm:ss"
+        />
       </el-form-item>
       </el-form-item>
       <el-form-item>
       <el-form-item>
-        <el-button type="primary" @click="handleSearch">搜索</el-button>
-        <el-button @click="resetQuery">重置</el-button>
-        <el-button type="primary" @click="handleExport">导出</el-button>
+        <el-button @click="handleQuery">
+          <Icon class="mr-5px" icon="ep:search" />
+          搜索
+        </el-button>
+        <el-button @click="resetQuery">
+          <Icon class="mr-5px" icon="ep:refresh" />
+          重置
+        </el-button>
+
+        <el-button type="primary" plain @click="openForm('create')">
+          <Icon icon="ep:plus" class="mr-5px" />
+          新建申请
+        </el-button>
+        <el-button
+          v-hasPermi="['system:inner:export']"
+          :loading="exportLoading"
+          plain
+          type="success"
+          @click="handleExport"
+        >
+          <Icon class="mr-5px" icon="ep:download" />
+          导出
+        </el-button>
       </el-form-item>
       </el-form-item>
     </el-form>
     </el-form>
+  </ContentWrap>
 
 
-    <!-- 数据表格 -->
-    <el-table :data="tableData" border>
-      <el-table-column prop="number" label="编号" width="120" />
-      <el-table-column prop="name" label="名称" width="150" />
-      <el-table-column prop="location" label="存放位置" />
-      <el-table-column label="图片" width="100">
+  <!-- 列表 -->
+  <ContentWrap>
+    <el-table v-loading="loading" :data="list">
+      <el-table-column align="center" label="标本名称" prop="name" />
+      <el-table-column align="center" label="开始日期" prop="startDate">
         <template #default="{ row }">
         <template #default="{ row }">
-          <el-image :src="row.image" style="width: 50px; height: 50px" />
+          {{ row.startDate ? dateFormatter(row.startDate) : 'N/A' }}
         </template>
         </template>
       </el-table-column>
       </el-table-column>
-      <el-table-column prop="returnBy" label="退还人" width="120" />
-      <el-table-column prop="returnTime" label="退还时间" width="180" />
-      <el-table-column prop="receiver" label="点收人" width="120" />
-      <el-table-column prop="status" label="回库状态" width="100">
+      <el-table-column align="center" label="结束日期" prop="endDate">
         <template #default="{ row }">
         <template #default="{ row }">
-          <el-tag :type="row.status === '已回库' ? 'success' : 'warning'">
-            {{ row.status }}
-          </el-tag>
+          {{ row.endDate ? dateFormatter(row.endDate) : 'N/A' }}
         </template>
         </template>
       </el-table-column>
       </el-table-column>
-      <el-table-column label="操作" width="220" fixed="right">
-        <template #default="{ row }">
-          <el-button type="primary" link @click="handleConfirm(row)">确认回库</el-button>
-          <el-button type="primary" link @click="handleEdit(row)">编辑</el-button>
-          <el-button type="danger" link @click="handleDelete(row)">删除</el-button>
+      <el-table-column align="center" label="退还人" prop="returnUser" />
+      <el-table-column align="center" label="点收人" prop="receiver" />
+      <el-table-column align="center" label="标本编号" prop="code" />
+      <el-table-column align="center" label="排序" prop="sort" />
+      <el-table-column align="center" label="备注" prop="remark" />
+      <el-table-column align="center" label="状态" prop="status">
+        <template #default="scope">
+          <dict-tag :type="DICT_TYPE.COMMON_STATUS" :value="scope.row.status" />
+        </template>
+      </el-table-column>
+      <el-table-column
+        :formatter="dateFormatter"
+        align="center"
+        label="创建时间"
+        prop="createTime"
+        width="180"
+      />
+      <el-table-column :width="220" align="center" label="操作">
+        <template #default="scope">
+          <el-button
+            v-hasPermi="['system:inner:update']"
+            link
+            type="primary"
+            @click="openForm('update', scope.row.id)"
+          >
+            编辑
+          </el-button>
+          <el-button
+            v-hasPermi="['system:inner:delete']"
+            link
+            type="danger"
+            @click="handleDelete(scope.row.id)"
+          >
+            删除
+          </el-button>
         </template>
         </template>
       </el-table-column>
       </el-table-column>
     </el-table>
     </el-table>
+  </ContentWrap>
+
+  <!-- 新增/编辑弹窗组件 -->
+  <InnerForm ref="formRef" @success="getList" />
 
 
-    <!-- 分页 -->
-    <el-pagination
-      v-model:current-page="queryParams.pageNum"
-      v-model:page-size="queryParams.pageSize"
-      :total="total"
-      layout="total, sizes, prev, pager, next, jumper"
-      @size-change="getList"
-      @current-change="getList"
-    />
-
-    <!-- 编辑弹窗 -->
-    <el-dialog v-model="dialogVisible" title="入库记录编辑">
-      <el-form ref="formRef" :model="form" :rules="rules" label-width="100px">
-        <el-form-item label="退还人" prop="returnBy">
-          <el-input v-model="form.returnBy" placeholder="请输入退还人姓名" />
-        </el-form-item>
-        <el-form-item label="点收人" prop="receiver">
-          <el-input v-model="form.receiver" placeholder="请输入点收人姓名" />
-        </el-form-item>
-        <el-form-item label="退还时间" prop="returnTime">
-          <el-date-picker
-            v-model="form.returnTime"
-            type="datetime"
-            placeholder="选择日期时间"
-          />
-        </el-form-item>
-        <el-form-item label="备注">
-          <el-input v-model="form.note" type="textarea" :rows="3" />
-        </el-form-item>
-      </el-form>
-      <template #footer>
-        <el-button @click="dialogVisible = false">取消</el-button>
-        <el-button type="primary" @click="submitForm">保存</el-button>
-      </template>
-    </el-dialog>
-  </div>
+  <!-- 分页组件 -->
+  <el-pagination
+    v-model:current-page="currentPage"
+    v-model:page-size="pageSize"
+    :total="total"
+    :page-sizes="[10, 20, 50, 100]"
+    @size-change="handleSizeChange"
+    @current-change="handlePageChange"
+  />
 </template>
 </template>
 
 
-<script setup>
-import { ref, reactive } from 'vue'
 
 
-const tableData = ref([
+
+<script setup lang="ts">
+
+import { dateFormatter } from '@/utils/formatTime'
+
+import InnerForm from './InnerForm.vue'
+import RoleApi from '@/api/system/role'
+// 本地模拟数据
+const mockData = [
   {
   {
     id: 1,
     id: 1,
-    number: 'RT-001',
-    name: '矿石标本',
-    location: 'B区-3柜',
-    image: 'https://via.placeholder.com/50',
-    returnBy: '张三',
-    returnTime: '2024-03-01 14:30:00',
-    receiver: '李四',
-    status: '已入库',
-    note: '包装完好'
-  }
-])
+    name: '',
+    code: '',
+    startDate: '',
+    endDate: '',
+    returnUser: '',
+    receiver: '',
+    sort: 1,
+    status: 0,
+    remark: '',
+    createTime: ''
+  },
 
 
-const queryParams = reactive({
-  pageNum: 1,
-  pageSize: 10,
-  name: '',
-  number: ''
-})
+]
 
 
-const form = reactive({
-  id: null,
-  returnBy: '',
-  receiver: '',
-  returnTime: '',
-  note: ''
-})
+// const loading = ref(false)
+// const total = ref(0)
+// const list = ref<any[]>([])
+
+// 分页相关
+const currentPage = ref(1)
+const pageSize = ref(10)
+
+// 查询列表(本地处理)
+// const getList = async () => {
+//   loading.value = true
+//   try {
+//     // 模拟过滤和分页
+//     const filteredData = mockData.filter(item => {
+//       const codeMatch = !queryParams.code || item.code.includes(queryParams.code)
+//       const statusMatch = queryParams.status === undefined || item.status === queryParams.status
+//       let dateMatch = true
+//       if (queryParams.createTime && queryParams.createTime.length === 2) {
+//         const itemDate = new Date(item.createTime).getTime()
+//         const startDate = new Date(queryParams.createTime[0]).getTime()
+//         const endDate = new Date(queryParams.createTime[1]).getTime()
+//         dateMatch = itemDate >= startDate && itemDate <= endDate
+//       }
+//       return codeMatch && statusMatch && dateMatch
+//     })
+//
+//     total.value = filteredData.length
+//     const start = (currentPage.value - 1) * pageSize.value
+//     const end = start + pageSize.value
+//     list.value = filteredData.slice(start, end)
+//   } finally {
+//     loading.value = false
+//   }
+// }
 
 
-const rules = {
-  returnBy: [{ required: true, message: '退还人不能为空', trigger: 'blur' }],
-  receiver: [{ required: true, message: '点收人不能为空', trigger: 'blur' }]
+// 删除处理
+const handleDelete = async (id: number) => {
+  try {
+    await message.delConfirm()
+    const index = mockData.findIndex(item => item.id === id)
+    if (index !== -1) {
+      mockData.splice(index, 1)
+      message.success(t('common.delSuccess'))
+      await getList()
+    }
+  } catch {}
 }
 }
+
+// 导出处理(本地数据)
+const handleExport = async () => {
+  try {
+    await message.exportConfirm()
+    exportLoading.value = true
+    // 构造导出数据
+    // const data = list.value.map(item => ({
+    //   标本名称: item.name,
+    //   标本编号: item.code,
+    //   开始日期: item.startDate,
+    //   结束日期: item.endDate,
+    //   状态: item.status === 0 ? '启用' : '停用',
+    //   创建时间: item.createTime
+    // }))
+    // download.excel(data, '标本列表.xls')
+  } finally {
+    exportLoading.value = false
+  }
+}
+// 新建
+const formRef = ref()
+const openForm = (type:string, id?:number ) =>{
+  formRef.value.open(type,id)
+
+}
+// 处理页码变化
+const handlePageChange = (page: number) => {
+  currentPage.value = page
+  getList()
+}
+
+// 处理每页条数变化
+const handleSizeChange = (size: number) => {
+  pageSize.value = size
+  currentPage.value = 1
+  getList()
+}
+
+
+
+
+/** 表单成功回调 */
+// const handleFormSuccess = () => {
+//   getList()
+// }
+
+onMounted(() => {
+  getList()
+})
 </script>
 </script>

+ 20 - 0
src/views/system/Out/ApproveForm.vue

@@ -0,0 +1,20 @@
+<template>
+  <el-dialog title="审批表单">
+    <el-form :model="formData" label-width="120px">
+      <el-form-item label="审批意见">
+        <el-input v-model="formData.opinion" type="textarea"/>
+      </el-form-item>
+    </el-form>
+    <template #footer>
+      <el-button @click="$emit('cancel')">取消</el-button>
+      <el-button type="primary" @click="$emit('submit')">提交</el-button>
+    </template>
+  </el-dialog>
+</template>
+
+<script setup>
+defineProps({
+  formData: Object
+})
+defineEmits(['cancel', 'submit'])
+</script>

+ 138 - 0
src/views/system/Out/OutForm.vue

@@ -0,0 +1,138 @@
+<template>
+  <Dialog v-model="dialogVisible" :title="dialogTitle">
+    <el-form
+      ref="formRef"
+      v-loading="formLoading"
+      :model="formData"
+      :rules="formRules"
+      label-width="80px"
+    >
+<!--      <el-form-item label="出库标本">-->
+<!--        <el-select v-model="formData.number" clearable placeholder="请选择出库标本">-->
+<!--          <el-option-->
+<!--            v-for="dict in getIntDictOptions(DICT_TYPE.COMMON_STATUS)"-->
+<!--            :key="dict.number"-->
+<!--            :label="dict.name"-->
+<!--            :value="dict.number"-->
+<!--          />-->
+<!--        </el-select>-->
+<!--      </el-form-item>-->
+
+<!--      <el-form-item label="出库人员">-->
+<!--        <el-select v-model="formData.number" clearable placeholder="请选择出库人员">-->
+<!--          <el-option-->
+<!--            v-for="dict in getIntDictOptions(DICT_TYPE.COMMON_STATUS)"-->
+<!--            :key="dict.number"-->
+<!--            :label="dict.name"-->
+<!--            :value="dict.number"-->
+<!--          />-->
+<!--        </el-select>-->
+<!--      </el-form-item>-->
+
+
+      <el-form-item label="申请编号" prop="id">
+        <el-input
+          v-model="formData.id"
+          class="!w-240px"
+          placeholder="请输入申请编号"
+        />
+      </el-form-item>
+      <el-form-item label="标本编号" prop="number">
+        <el-input v-model="formData.number" placeholder="请输入标本编号" />
+      </el-form-item>
+
+
+
+    </el-form>
+    <template #footer>
+      <el-button :disabled="formLoading" type="primary" @click="submitForm">确 定</el-button>
+      <el-button @click="dialogVisible = false">取 消</el-button>
+    </template>
+  </Dialog>
+</template>
+<script lang="ts" setup>
+
+import { CommonStatusEnum } from '@/utils/constants'
+
+import * as OutBoundApi from '@/api/system/Out'
+import {DICT_TYPE, getIntDictOptions} from "@/utils/dict";
+import {updateForm} from "@/api/system/Out";
+
+
+defineOptions({ name: 'SystemOutForm' })
+
+const { t } = useI18n() // 国际化
+const message = useMessage() // 消息弹窗
+
+const dialogVisible = ref(false) // 弹窗的是否展示
+const dialogTitle = ref('') // 弹窗的标题
+const formLoading = ref(false) // 表单的加载中:1)修改时的数据加载;2)提交的按钮禁用
+const formType = ref('') // 表单的类型:create - 新增;update - 修改
+const formData = ref({
+  id: undefined,
+  // name: '',
+  // code: '',
+  // sort: undefined,
+  // status: CommonStatusEnum.ENABLE,
+  // remark: ''
+
+  number:""
+})
+const formRules = reactive({
+ })
+const formRef = ref() // 表单 Ref
+
+/** 打开弹窗 */
+const open = async (type: string, id?: number) => {
+  dialogVisible.value = true
+  dialogTitle.value = t('action.' + type)
+  formType.value = type
+  resetForm()
+  // 修改时,设置数据
+  if (id) {
+    formLoading.value = true
+    try {
+      formData.value = await OutBoundApi.getRole(id)
+    } finally {
+      formLoading.value = false
+    }
+  }
+}
+
+/** 重置表单 */
+const resetForm = () => {
+  formData.value = {
+    id: undefined,
+    number:""
+  }
+  formRef.value?.resetFields()
+}
+defineExpose({ open }) // 提供 open 方法,用于打开弹窗
+
+/** 提交表单 */
+const emit = defineEmits(['success']) // 定义 success 事件,用于操作成功后的回调
+const submitForm = async () => {
+//   校验表单
+  if (!formRef) return
+  const valid = await formRef.value.validate()
+  if (!valid) return
+  //提交请求
+  formLoading.value = true
+  try {
+    const data = formData.value as unknown as OutBoundApi.OouBoundVO
+    if (formType.value === 'create') {
+      console.log(data,'新增时')
+      await OutBoundApi.createOutBound(data)
+      message.success(t('common.createSuccess'))
+    } else {
+      await OutBoundApi.updateForm(data)
+      message.success(t('common.updateSuccess'))
+    }
+    dialogVisible.value = false
+    // 发送操作成功的事件
+    emit('success')
+  } finally {
+    formLoading.value = false
+  }
+}
+  </script>

+ 0 - 134
src/views/system/Out/iker.vue

@@ -1,134 +0,0 @@
-<template>
-  <div class="role-management">
-    <!-- 搜索区域 -->
-    <el-card class="search-area">
-      <el-form :inline="true">
-        <el-form-item label="角色名称">
-          <el-input v-model="searchForm.name" placeholder="请输入角色名称" />
-        </el-form-item>
-        <el-form-item label="角色标识">
-          <el-input v-model="searchForm.identifier" placeholder="请输入角色标识" />
-        </el-form-item>
-        <el-form-item label="状态">
-          <el-select v-model="searchForm.status" placeholder="请选择状态">
-            <el-option label="全部" value="" />
-            <el-option label="开启" value="1" />
-            <el-option label="关闭" value="0" />
-          </el-select>
-        </el-form-item>
-        <el-form-item>
-          <el-button type="primary" @click="handleSearch">搜索</el-button>
-          <el-button type="success" @click="handleAdd">新增</el-button>
-          <el-button @click="handleExport">导出</el-button>
-        </el-form-item>
-      </el-form>
-    </el-card>
-
-    <!-- 数据表格 -->
-    <el-table :data="filteredRoles" border style="width: 100%">
-      <el-table-column prop="id" label="角色编号" width="100" />
-      <el-table-column prop="name" label="角色名称" width="150" />
-      <el-table-column prop="type" label="角色类型" width="120" />
-      <el-table-column prop="identifier" label="角色标识" width="180" />
-      <el-table-column prop="order" label="显示顺序" width="100" />
-      <el-table-column prop="remark" label="备注" />
-      <el-table-column prop="status" label="状态" width="100">
-        <template #default="{ row }">
-          <el-tag :type="row.status ? 'success' : 'danger'">
-            {{ row.status ? '开启' : '关闭' }}
-          </el-tag>
-        </template>
-      </el-table-column>
-      <el-table-column prop="createTime" label="创建时间" width="180" />
-      <el-table-column label="操作" width="220">
-        <template #default="{ row }">
-          <el-button link type="primary" @click="handleEdit(row)">编辑</el-button>
-          <el-button link type="primary" @click="handleMenuAuth(row)">菜单权限</el-button>
-          <el-button link type="primary" @click="handleDataAuth(row)">数据权限</el-button>
-          <el-button link type="danger" @click="handleDelete(row)">删除</el-button>
-        </template>
-      </el-table-column>
-    </el-table>
-  </div>
-</template>
-
-<script setup>
-import { ref, computed } from 'vue'
-
-// 模拟数据
-const roles = ref([
-  {
-    id: 101,
-    name: '测试账号',
-    type: '自定义',
-    identifier: '测试',
-    order: 0,
-    remark: '',
-    status: 1,
-    createTime: '2021-01-06 13:49:35'
-  },
-  // 其他数据...
-])
-
-// 搜索表单
-const searchForm = ref({
-  name: '',
-  identifier: '',
-  status: ''
-})
-
-// 过滤后的数据
-const filteredRoles = computed(() => {
-  return roles.value.filter(role => {
-    return (
-      role.name.includes(searchForm.value.name) &&
-      role.identifier.includes(searchForm.value.identifier) &&
-      (searchForm.value.status === '' ||
-        role.status.toString() === searchForm.value.status)
-    )
-  })
-})
-
-// 操作方法
-const handleSearch = () => {
-  // 搜索逻辑
-}
-
-const handleAdd = () => {
-  // 新增逻辑
-}
-
-const handleExport = () => {
-  // 导出逻辑
-}
-
-const handleEdit = (row) => {
-  // 编辑逻辑
-}
-
-const handleMenuAuth = (row) => {
-  // 菜单权限设置
-}
-
-const handleDataAuth = (row) => {
-  // 数据权限设置
-}
-
-const handleDelete = (row) => {
-  // 删除逻辑
-}
-</script>
-
-<style scoped>
-.search-area {
-  margin-bottom: 20px;
-}
-
-.el-form-item {
-  margin-bottom: 0;
-}
-
-.el-table {
-  margin-top: 20px;
-}
-</style>

+ 269 - 0
src/views/system/Out/iker(出库管理).vue

@@ -0,0 +1,269 @@
+<template>
+  <contentWrap>
+    <!-- 搜索工作栏 -->
+    <el-form
+      ref="queryFormRef"
+      :inline="true"
+      :model="queryParams"
+      class="-mb-15px"
+      label-width="68px"
+    >
+      <el-form-item label="名称" prop="name">
+        <el-input
+          v-model="queryParams.name"
+          class="!w-240px"
+          clearable
+          placeholder="请输入名称"
+          @keyup.enter="handleQuery"
+        />
+      </el-form-item>
+      <el-form-item label="用途" prop="use">
+        <el-input
+          v-model="queryParams.use"
+          class="!w-240px"
+          clearable
+          placeholder="请输入用途"
+          @keyup.enter="handleQuery"
+        />
+      </el-form-item>
+      <el-form-item label="开始时间" prop="startTime">
+        <el-date-picker
+          v-model="queryParams.startTime"
+          class="!w-240px"
+          type="daterange"
+          range-separator="-"
+          start-placeholder="开始日期"
+          end-placeholder="结束日期"
+          value-format="YYYY-MM-DD HH:mm:ss"
+        />
+      </el-form-item>
+      <el-form-item>
+        <el-button @click="handleQuery">
+          <Icon class="mr-5px" icon="ep:search" />
+          搜索
+        </el-button>
+        <el-button @click="resetQuery">
+          <Icon class="mr-5px" icon="ep:refresh" />
+          重置
+        </el-button>
+        <el-button
+
+          plain
+          type="primary"
+          @click="openForm('create')"
+        >
+          <Icon class="mr-5px" icon="ep:plus" />
+          新增
+        </el-button>
+      </el-form-item>
+    </el-form>
+
+    <!-- 表格 -->
+    <el-table v-loading="loading" :data="list">
+      <el-table-column align="center" label="编号" prop="number" />
+      <el-table-column align="center" label="名称" prop="name" />
+      <el-table-column align="center" label="用途" prop="use" />
+      <el-table-column align="center" label="显示顺序" prop="sort" />
+      <el-table-column align="center" label="开始时间" prop="remark" />
+      <el-table-column align="center" label="结束时间" prop="remark" />
+      <el-table-column align="center" label="备注" prop="remark" />
+      <el-table-column
+        :formatter="dateFormatter"
+        align="center"
+        label="创建时间"
+        prop="createTime"
+        width="180"
+      />
+      <el-table-column align="center" label="操作" width="120">
+        <template #default="scope">
+          <el-button
+            link
+            type="danger"
+            @click="handleDelete(scope.row.id)"
+          >
+            删除
+          </el-button>
+
+        </template>
+      </el-table-column>
+    </el-table>
+    <!-- 新增对话框 -->
+    <el-dialog
+      v-model="formVisible"
+      :title="formType === 'create' ? '新增' : '修改'"
+      width="500px"
+    >
+      <el-form
+        ref="formRef"
+        :model="formData"
+        :rules="formRules"
+        label-width="80px"
+      >
+        <el-form-item label="名称" prop="name">
+          <el-input v-model="formData.name" placeholder="请输入名称" />
+        </el-form-item>
+        <el-form-item label="用途" prop="use">
+          <el-input v-model="formData.use" placeholder="请输入用途" />
+        </el-form-item>
+        <el-form-item label="显示顺序" prop="sort">
+          <el-input-number v-model="formData.sort" :min="0" />
+        </el-form-item>
+        <el-form-item label="时间范围">
+          <el-date-picker
+            v-model="formData.timeRange"
+            type="daterange"
+            range-separator="-"
+            start-placeholder="开始日期"
+            end-placeholder="结束日期"
+            value-format="YYYY-MM-DD HH:mm:ss"
+          />
+        </el-form-item>
+        <el-form-item label="备注" prop="remark">
+          <el-input v-model="formData.remark" type="textarea" />
+        </el-form-item>
+      </el-form>
+
+      <template #footer>
+        <el-button @click="formVisible = false">取消</el-button>
+        <el-button type="primary" @click="submitForm">提交</el-button>
+      </template>
+    </el-dialog>
+  </contentWrap>
+  <!-- 表单弹窗:添加/修改 -->
+  <RoleForm ref="formRef" @success="getList" />
+</template>
+
+<script lang="ts" setup>
+import { ref, reactive, onMounted } from 'vue'
+import { ElMessage, ElMessageBox } from 'element-plus'
+import { useI18n } from 'vue-i18n'
+import { dateFormatter } from '@/utils/formatTime'
+import RoleForm from "@/views/system/role/RoleForm.vue";
+import * as UserApi from '@/api/system/user'
+
+import * as OutBoundApi from '@/api/system/Out'
+
+const { t } = useI18n()
+
+const loading = ref(true)
+const list = ref([])
+const queryParams = reactive({
+  pageNo: 1,
+  pageSize: 10,
+  name: undefined,
+  use: undefined,
+  startTime: [] as string[],
+})
+const queryFormRef = ref()
+
+/** 查询列表 */
+const getList = async () => {
+  loading.value = true
+  try {
+    // const data = await UserApi.getUserPage(queryParams)
+    const data = [];
+    list.value = data.list
+  } finally {
+    loading.value = false
+  }
+}
+
+/** 搜索按钮操作 */
+const handleQuery = () => {
+  queryParams.pageNo = 1
+  getList()
+}
+
+/** 删除按钮操作 */
+const handleDelete = async (id: number) => {
+  try {
+    await ElMessageBox.confirm(t('common.delConfirm'), t('common.reminder'), {
+      confirmButtonText: t('common.confirm'),
+      cancelButtonText: t('common.cancel'),
+      type: 'warning',
+    })
+    await UserApi.deleteUser(id)
+    ElMessage.success(t('common.delSuccess'))
+    await getList()
+  } catch {}
+}
+
+/** 打开表单 */
+const openForm = (type: string, id?: number) => {
+  // 这里需要实现表单组件逻辑
+  console.log('打开表单', type, id)
+}
+// // 新增以下类型定义
+// interface FormData {
+//   id?: number
+//   name: string
+//   use: string
+//   sort: number
+//   timeRange: string[]
+//   remark: string
+// }
+//
+// // 在setup()中添加以下变量
+// const formVisible = ref(false)
+// const formType = ref('')
+// const formRef = ref()
+// const formData = ref<FormData>({
+//   name: '',
+//   use: '',
+//   sort: 0,
+//   timeRange: [],
+//   remark: ''
+// })
+//
+// // 表单验证规则
+// const formRules = reactive({
+//   name: [{ required: true, message: '名称不能为空', trigger: 'blur' }],
+//   use: [{ required: true, message: '用途不能为空', trigger: 'blur' }],
+//   sort: [{ required: true, message: '显示顺序不能为空', trigger: 'blur' }]
+// })
+//
+// // 修改openForm方法
+// const openForm = (type: string, row?: any) => {
+//   formType.value = type
+//   if (type === 'create') {
+//     formData.value = {
+//       name: '',
+//       use: '',
+//       sort: 0,
+//       timeRange: [],
+//       remark: ''
+//     }
+//   } else {
+//     // 编辑逻辑(如果需要)
+//   }
+//   formVisible.value = true
+// }
+//
+// // 新增提交方法
+// const submitForm = async () => {
+//   await formRef.value.validate()
+//   try {
+//     loading.value = true
+//     // 构造请求参数
+//     const params = {
+//       ...formData.value,
+//       startTime: formData.value.timeRange[0],
+//       endTime: formData.value.timeRange[1]
+//     }
+//     delete params.timeRange
+//
+//     // 调用API(需要实现)
+//     // await UserApi.createUser(params)
+//     ElMessage.success('新增成功')
+//     formVisible.value = false
+//     await getList() // 刷新列表
+//   } catch (error) {
+//     console.error('新增失败', error)
+//   } finally {
+//     loading.value = false
+//   }
+// }
+// onMounted(() => {
+//   getList()
+// })
+</script>

+ 0 - 213
src/views/system/Out/index.vue

@@ -1,213 +0,0 @@
-<template>
-  <div class="app-container">
-    <!-- 搜索栏 -->
-    <el-form :model="queryParams" inline>
-      <el-form-item label="名称">
-        <el-input v-model="queryParams.name" placeholder="请输入标本名称" clearable />
-      </el-form-item>
-      <el-form-item label="编号">
-        <el-input v-model="queryParams.number" placeholder="请输入标本编号" clearable />
-      </el-form-item>
-      <el-form-item>
-        <el-button type="primary" @click="handleSearch">搜索</el-button>
-        <el-button @click="resetQuery">重置</el-button>
-        <el-button type="primary" @click="handleAdd">新增</el-button>
-        <el-button type="warning" @click="handleExport">导出</el-button>
-      </el-form-item>
-    </el-form>
-
-    <!-- 数据表格 -->
-    <el-table :data="tableData" border>
-      <el-table-column prop="number" label="编号" width="120" />
-      <el-table-column prop="name" label="名称" width="150" />
-      <el-table-column prop="location" label="存放位置" />
-      <el-table-column label="图片" width="100">
-        <template #default="{ row }">
-          <el-image :src="row.image" style="width: 50px; height: 50px" />
-        </template>
-      </el-table-column>
-      <el-table-column prop="status" label="状态" width="100">
-        <template #default="{ row }">
-          <el-switch
-            v-model="row.status"
-            :active-value="1"
-            :inactive-value="0"
-            active-text="启用"
-            inactive-text="停用"
-            @change="handleStatusChange(row)"
-          />
-        </template>
-      </el-table-column>
-      <el-table-column prop="createTime" label="创建时间" width="180" />
-      <el-table-column label="操作" width="220" fixed="right">
-        <template #default="{ row }">
-          <el-button type="primary" link @click="handleEdit(row)">编辑</el-button>
-          <el-button type="primary" link @click="handlePermission(row)">权限</el-button>
-          <el-button type="danger" link @click="handleDelete(row)">删除</el-button>
-        </template>
-      </el-table-column>
-    </el-table>
-
-    <!-- 分页 -->
-    <el-pagination
-      v-model:current-page="queryParams.pageNum"
-      v-model:page-size="queryParams.pageSize"
-      :total="total"
-      layout="total, sizes, prev, pager, next, jumper"
-      @size-change="getList"
-      @current-change="getList"
-    />
-
-    <!-- 新增/编辑弹窗 -->
-    <el-dialog v-model="dialogVisible" :title="dialogTitle">
-      <el-form ref="formRef" :model="form" :rules="rules" label-width="100px">
-        <el-form-item label="标本名称" prop="name">
-          <el-input v-model="form.name" placeholder="请输入标本名称" />
-        </el-form-item>
-        <el-form-item label="标本编号" prop="number">
-          <el-input v-model="form.number" placeholder="请输入标本编号" />
-        </el-form-item>
-        <el-form-item label="存放位置" prop="location">
-          <el-input v-model="form.location" placeholder="请输入存放位置" />
-        </el-form-item>
-        <el-form-item label="图片">
-          <el-upload
-            action="https://jsonplaceholder.typicode.com/posts/"
-            :show-file-list="false"
-            :on-success="handleUploadSuccess"
-          >
-            <el-button type="primary">点击上传</el-button>
-          </el-upload>
-        </el-form-item>
-      </el-form>
-      <template #footer>
-        <el-button @click="dialogVisible = false">取 消</el-button>
-        <el-button type="primary" @click="submitForm">确 定</el-button>
-      </template>
-    </el-dialog>
-  </div>
-</template>
-
-<script setup>
-import { ref, reactive } from 'vue'
-
-// 表格数据
-const tableData = ref([
-  {
-    id: 1,
-    number: 'SP-001',
-    name: '植物标本',
-    location: 'A区-1柜',
-    image: 'https://via.placeholder.com/50',
-    status: 1,
-    createTime: '2024-03-01 10:00:00'
-  }
-])
-
-// 查询参数
-const queryParams = reactive({
-  pageNum: 1,
-  pageSize: 10,
-  name: '',
-  number: ''
-})
-
-// 表单数据
-const form = reactive({
-  id: null,
-  name: '',
-  number: '',
-  location: '',
-  image: ''
-})
-
-// 表单验证规则
-const rules = {
-  name: [{ required: true, message: '名称不能为空', trigger: 'blur' }],
-  number: [{ required: true, message: '编号不能为空', trigger: 'blur' }]
-}
-
-// 弹窗控制
-const dialogVisible = ref(false)
-const dialogTitle = ref('')
-const formRef = ref()
-
-// 获取数据列表
-const getList = async () => {
-  // 这里调用API接口
-  console.log('获取列表数据', queryParams)
-}
-
-// 搜索
-const handleSearch = () => {
-  queryParams.pageNum = 1
-  getList()
-}
-
-// 重置查询
-const resetQuery = () => {
-  Object.assign(queryParams, {
-    pageNum: 1,
-    name: '',
-    number: ''
-  })
-  getList()
-}
-
-// 新增
-const handleAdd = () => {
-  dialogTitle.value = '新增标本'
-  Object.keys(form).forEach(key => (form[key] = ''))
-  dialogVisible.value = true
-}
-
-// 编辑
-const handleEdit = (row) => {
-  dialogTitle.value = '编辑标本'
-  Object.assign(form, row)
-  dialogVisible.value = true
-}
-
-// 删除
-const handleDelete = (row) => {
-  ElMessageBox.confirm('确认删除该记录吗?', '警告', {
-    type: 'warning'
-  }).then(() => {
-    // 调用删除API
-    console.log('删除成功')
-    getList()
-  })
-}
-
-// 状态修改
-const handleStatusChange = (row) => {
-  ElMessage.success('状态修改成功')
-  // 调用状态修改API
-}
-
-// 提交表单
-const submitForm = () => {
-  formRef.value.validate(valid => {
-    if (valid) {
-      // 调用新增/修改API
-      dialogVisible.value = false
-      ElMessage.success('操作成功')
-      getList()
-    }
-  })
-}
-
-// 文件上传
-const handleUploadSuccess = (response) => {
-  form.image = response.url // 根据实际接口调整
-}
-
-// 初始化获取数据
-getList()
-</script>
-
-<style scoped>
-.app-container {
-  padding: 20px;
-}
-</style>

+ 234 - 0
src/views/system/Out/index(出库申请).vue

@@ -0,0 +1,234 @@
+<template>
+  <ContentWrap>
+    <!-- 搜索工作栏 -->
+    <el-form
+      ref="queryFormRef"
+      :inline="true"
+      :model="queryParams"
+      class="-mb-15px"
+      label-width="100px"
+    >
+      <el-form-item label="申请编号" prop="id">
+        <el-input
+          v-model="queryParams.id"
+          class="!w-240px"
+          placeholder="请输入申请编号"
+        />
+      </el-form-item>
+      <el-form-item label="标本名称" prop="sampleName">
+        <el-input
+          v-model="queryParams.sampleName"
+          class="!w-240px"
+          placeholder="请输入标本名称"
+        />
+      </el-form-item>
+      <el-form-item label="申请状态" prop="status">
+        <el-select v-model="queryParams.status" class="!w-240px" clearable>
+          <el-option
+            v-for="item in statusOptions"
+            :key="item.value"
+            :label="item.label"
+            :value="item.value"
+          />
+        </el-select>
+      </el-form-item>
+      <el-form-item label="申请时间" prop="applyTime">
+        <el-date-picker
+          v-model="queryParams.applyTime"
+          type="daterange"
+          range-separator="-"
+          start-placeholder="开始日期"
+          end-placeholder="结束日期"
+          class="!w-340px"
+        />
+      </el-form-item>
+      <el-form-item>
+        <el-button type="primary" @click="handleQuery">
+          <Icon icon="ep:search" class="mr-5px" />
+          搜索
+        </el-button>
+        <el-button @click="resetQuery">
+          <Icon icon="ep:refresh" class="mr-5px" />
+          重置
+        </el-button>
+        <el-button type="primary" plain @click="openForm('create')">
+          <Icon icon="ep:plus" class="mr-5px" />
+          新建申请
+        </el-button>
+      </el-form-item>
+    </el-form>
+  </ContentWrap>
+<!--  列表-->
+  <ContentWrap>
+      <el-table v-loading="loading" :data="list">
+        <el-table-column align="center" label="申请编号" prop="id" width="100" />
+        <el-table-column label="标本编号" align="center" prop="number" width="120" />
+<!--        <el-table-column label="出库类型" align="center" prop="outType" width="120">-->
+<!--          <template #default="scope">-->
+<!--            <dict-tag :type="DICT_TYPE.SPECIMEN_OUT_TYPE" :value="scope.row.outType" />-->
+<!--          </template>-->
+<!--        </el-table-column>-->
+
+        <el-table-column label="标本名称" align="center" prop="sampleName" width="120" />
+        <el-table-column label="申请人" align="center" prop="applicant" width="120" />
+        <el-table-column label="申请数量" align="center" prop="quantity" width="100" />
+<!--        <el-table-column label="申请时间" align="center" prop="applyTime" width="180">-->
+<!--          <template #default="scope">-->
+<!--            {{ dateFormatter(scope.row.applyTime) }}-->
+<!--          </template>-->
+<!--        </el-table-column>-->
+<!--        <el-table-column label="状态" align="center" prop="status" width="100">-->
+<!--          <template #default="scope">-->
+<!--            <dict-tag :type="DICT_TYPE.SPECIMEN_OUT_STATUS" :value="scope.row.status" />-->
+<!--          </template>-->
+<!--        </el-table-column>-->
+        <el-table-column label="备注" align="center" prop="remark" />
+        <el-table-column label="操作" align="center" width="220">
+          <template #default="scope">
+            <el-button
+              link
+              type="primary"
+              @click="openForm('update', scope.row.id)"
+            >
+              编辑
+            </el-button>
+          </template>
+        </el-table-column>
+
+      </el-table>
+
+    <!-- 分页 -->
+    <Pagination
+      :page="queryParams.pageNo"
+      :limit="queryParams.pageSize"
+      :total="total"
+    />
+  </ContentWrap>
+  <!-- 表单弹窗:添加/修改 -->
+  <OutForm ref="formRef" @success="getList" />
+</template>
+
+<script lang="ts" setup>
+import OutForm from './OutForm.vue'
+
+// import ApproveForm from './approveForm.vue'
+import * as OutBoundApi from '@/api/system/Out/index'
+// import * as UserApi from "@/api/system/user";
+// 模拟数据
+// const mockData = [
+//   {
+//     applyNo: '0',
+//     sampleName: '0',
+//     applicant: '0',
+//     applyTime: '0',
+//     quantity: 0,
+//     status: 0
+//   },
+//   {
+//     applyNo: '1',
+//     sampleName: '1',
+//     applicant: '1',
+//     applyTime: '1',
+//     quantity: 1,
+//     status: 1
+//   },
+//
+// ]
+
+// 状态选项
+const statusOptions = [
+  { value: 1, label: '待审批' },
+  { value: 2, label: '已通过' },
+  { value: 3, label: '已拒绝' }
+]
+
+// 状态标签类型映射
+const statusTagMap = {
+  1: 'warning',
+  2: 'success',
+  3: 'danger'
+}
+const queryFormRef = ref()
+
+// 查询参数
+const queryParams = reactive({
+  pageNo: 1,
+  pageSize: 10,
+  id: undefined,
+  sampleName: undefined,
+  status: undefined,
+  applyTime: undefined
+})
+
+const loading = ref(false)
+// const total = ref(mockData.length)
+
+const list = ref([])
+const total = ref()
+const getList = async () => {
+  loading.value = true
+  try {
+    const data = await OutBoundApi.getPage(queryParams)
+    console.log(data,'1')
+    list.value = data.list
+    total.value = data.total
+  } finally {
+    loading.value = false
+  }
+}
+
+
+// 搜索处理
+const handleQuery = () => {
+  queryParams.pageNo = 1
+  console.log(queryParams,'搜索时')
+  getList()
+}
+
+// 重置查询
+const resetQuery = () => {
+  queryFormRef.value?.resetFields()
+  handleQuery()
+}
+
+// 新建申请
+const formRef = ref()
+const openForm = (type:string, id?:number ) =>{
+  formRef.value.open(type,id)
+
+}
+
+// 编辑操作
+// const handleEdit = (row: any) => {
+//   ElMessage.info(`编辑申请 ${row.applyNo}`)
+// }
+
+// 审批操作
+// const handleApprove = (row: any) => {
+//   ElMessageBox.confirm(`确认审批申请 ${row.applyNo}?`, '提示', {
+//     confirmButtonText: '确认',
+//     cancelButtonText: '取消',
+//     type: 'warning'
+//   }).then(() => {
+//     ElMessage.success('审批操作成功')
+//   })
+// }
+
+// 删除操作
+// const handleDelete = (row: any) => {
+//   ElMessageBox.confirm(`确认删除申请 ${row.applyNo}?`, '警告', {
+//     confirmButtonText: '确认',
+//     cancelButtonText: '取消',
+//     type: 'error'
+//   }).then(() => {
+//     ElMessage.success('删除成功')
+//   })
+// }
+// const showApproveForm = ref(false)
+// const showOutForm = ref(false)
+
+onMounted( ()=>{
+  getList();
+})
+</script>
+

+ 0 - 108
uno.config.ts

@@ -1,108 +0,0 @@
-import { defineConfig, toEscapedSelector as e, presetUno } from 'unocss'
-// import transformerVariantGroup from '@unocss/transformer-variant-group'
-
-export default defineConfig({
-  // ...UnoCSS options
-  rules: [
-    [
-      /^custom-hover$/,
-      ([], { rawSelector }) => {
-        const selector = e(rawSelector)
-        return `
-${selector} {
-  display: flex;
-  height: 100%;
-  padding: 0 10px;
-  cursor: pointer;
-  align-items: center;
-  transition: background var(--transition-time-02);
-}
-/* you can have multiple rules */
-${selector}:hover {
-  background-color: var(--top-header-hover-color);
-}
-.dark ${selector}:hover {
-  background-color: var(--el-bg-color-overlay);
-}
-`
-      }
-    ],
-    [
-      /^layout-border__left$/,
-      ([], { rawSelector }) => {
-        const selector = e(rawSelector)
-        return `
-${selector}:before {
-  content: "";
-  position: absolute;
-  top: 0;
-  left: 0;
-  width: 1px;
-  height: 100%;
-  background-color: var(--el-border-color);
-  z-index: 3;
-}
-`
-      }
-    ],
-    [
-      /^layout-border__right$/,
-      ([], { rawSelector }) => {
-        const selector = e(rawSelector)
-        return `
-${selector}:after {
-  content: "";
-  position: absolute;
-  top: 0;
-  right: 0;
-  width: 1px;
-  height: 100%;
-  background-color: var(--el-border-color);
-  z-index: 3;
-}
-`
-      }
-    ],
-    [
-      /^layout-border__top$/,
-      ([], { rawSelector }) => {
-        const selector = e(rawSelector)
-        return `
-${selector}:before {
-  content: "";
-  position: absolute;
-  top: 0;
-  left: 0;
-  width: 100%;
-  height: 1px;
-  background-color: var(--el-border-color);
-  z-index: 3;
-}
-`
-      }
-    ],
-    [
-      /^layout-border__bottom$/,
-      ([], { rawSelector }) => {
-        const selector = e(rawSelector)
-        return `
-${selector}:after {
-  content: "";
-  position: absolute;
-  bottom: 0;
-  left: 0;
-  width: 100%;
-  height: 1px;
-  background-color: var(--el-border-color);
-  z-index: 3;
-}
-`
-      }
-    ]
-  ],
-  presets: [presetUno({ dark: 'class', attributify: false })],
-  // transformers: [transformerVariantGroup()],
-  shortcuts: {
-    'wh-full': 'w-full h-full'
-  }
-})