Просмотр исходного кода

✨feat:新增电脑信息详情页、编辑电脑信息页

xinyan 8 месяцев назад
Родитель
Сommit
234bcdaffe

+ 22 - 0
src/views/computer-information/api.ts

@@ -11,3 +11,25 @@ export function getCardData(query: any) {
   });
 }
 
+export function getComputerDetailOverview(id: number) {
+  return request({
+		url: `${apiPrefix}${id}/`,
+		method: 'GET',
+	});
+}
+
+export function getCurrentTableData(query: any) {
+  return request({
+    url: apiPrefix + 'current/',
+    method: 'GET',
+    params: query,
+  });
+}
+export function getPastTableData(query: any) {
+  return request({
+    url: apiPrefix + 'past/',
+    method: 'GET',
+    params: query,
+  });
+}
+

+ 175 - 73
src/views/computer-information/components/ComputerDetail.vue

@@ -1,94 +1,196 @@
-<script setup lang="ts">/**
+<script lang="ts" setup>
+/**
  * @Name: ComputerDetail.vue
  * @Description: 电脑信息-当前
  * @Author: xinyan
  */
+import { useResponse } from '/@/utils/useResponse';
 import { ComputerColumns } from '/@/views/computer-information/useColumns';
+import * as api from '../api';
+import { Picture as IconPicture } from '@element-plus/icons-vue';
+import { useTableData } from '/@/utils/useTableData';
+import { usePagination } from '/@/utils/usePagination';
+
+const route = useRoute();
+const id = route.query.id;
+const computerOverview: any = ref([]);
+const overviewLoading = ref();
+const currentView = ref('history');
+const { tableOptions, handlePageChange } = usePagination(fetchComputerData);
 
 const gridOptions: any = reactive({
-  border: 'inner',
-  round: true,
-  stripe: true,
-  currentRowHighLight: true,
-  height: 870,
-  toolbarConfig: {
-    custom: true,
-    slots: {
-      buttons: 'toolbar_buttons'
-      // tools: 'toolbar_tools'
-    }
-  },
-  rowConfig: {
-    isHover: true
-  },
-  columnConfig: {
-    resizable: true
-  },
-  pagerConfig: {
-    total: 0,
-    page: 1,
-    limit: 10
-  },
-  loading: false,
-  loadingConfig: {
-    icon: 'vxe-icon-indicator roll',
-    text: '正在拼命加载中...'
-  },
-  columns: ComputerColumns,
-  data: []
+	border: 'inner',
+	round: true,
+	stripe: true,
+	currentRowHighLight: true,
+	height: 700,
+	toolbarConfig: {
+		custom: true,
+		slots: {
+			buttons: 'toolbar_buttons',
+			// tools: 'toolbar_tools'
+		},
+	},
+	rowConfig: {
+		isHover: true,
+	},
+	columnConfig: {
+		resizable: true,
+	},
+	pagerConfig: {
+		total: tableOptions.value.total,
+		page: tableOptions.value.page,
+		limit: tableOptions.value.limit,
+	},
+	loading: false,
+	loadingConfig: {
+		icon: 'vxe-icon-indicator roll',
+		text: '正在拼命加载中...',
+	},
+	columns: ComputerColumns,
+	data: [],
+});
+
+function pageChange({ pageSize, currentPage }: any) {
+	gridOptions.pagerConfig.limit = pageSize;
+	gridOptions.pagerConfig.page = currentPage;
+	fetchComputerData();
+}
+
+// 当前信息、历史记录
+async function fetchComputerData() {
+	const query = {
+		id: id,
+		page: gridOptions.pagerConfig.page,
+		limit: gridOptions.pagerConfig.limit,
+	};
+	switch (currentView.value) {
+		case 'current':
+			currentView.value = 'history';
+			await useTableData(api.getPastTableData, query, gridOptions);
+			break;
+		case 'history':
+			currentView.value = 'current';
+			await useTableData(api.getCurrentTableData, query, gridOptions);
+	}
+}
+
+async function fetchComputerDetailOverview() {
+	const res = await useResponse(id, api.getComputerDetailOverview, overviewLoading);
+	computerOverview.value = res.data;
+}
+
+const getImageSrc = () => {
+	// 如果 `images` 有值,则返回第一张图片的 URL;否则返回占位图
+	return computerOverview.value.images && computerOverview.value.images.length > 0
+		? computerOverview.value.images[0].image_url
+		: 'https://via.placeholder.com/150';
+};
+
+// 表格样式
+const cellStyle = () => {
+	return {
+		fontSize: '12px',
+		fontWeight: '600',
+	};
+};
+
+const headerCellStyle = () => {
+	return {
+		fontSize: '12px',
+	};
+};
+
+onMounted(() => {
+	fetchComputerData();
+	fetchComputerDetailOverview();
 });
 </script>
 
 <template>
-  <div class="p-2.5">
-    <!-- overview-card -->
-    <el-card body-class="flex items-center" shadow="hover" style="border: none">
-      <el-image :src="`https://via.placeholder.com/150`" class="mr-7 rounded-2xl" style="height: 100px; width: 100px; object-fit: contain">
-        <template #error>
-          <div class="mr-3.5 flex items-center justify-center text-5xl" style="height: 100px; width: 100px; background-color: #f5f5f5">
-            <el-icon>
-              <icon-picture />
-            </el-icon>
-          </div>
-        </template>
-      </el-image>
-      <el-col :span="18">
-        <div class="info-container">
-          <div class="info-column">
-            <div class="font-semibold">电脑编号:</div>
-            <div class="font-semibold">所属部门:</div>
-            <div class="font-semibold">工位号:</div>
-            <div class="font-semibold">IP地址:</div>
-          </div>
-          <div class="info-column">
-            <div class="font-semibold">电脑名称:</div>
-            <div class="font-semibold">使用人:</div>
-            <div class="font-semibold">电脑类型:</div>
-            <div class="font-semibold">MAC地址:</div>
-          </div>
-        </div>
-      </el-col>
-    </el-card>
-    <!-- table-card -->
-    <el-card body-style="padding-top: 10px" class="mt-2.5" shadow="hover" style="border: none">
-      <vxe-grid v-bind="gridOptions">
-      </vxe-grid>
-    </el-card>
-  </div>
+	<div class="p-2.5">
+		<!-- overview-card -->
+		<el-card v-loading="overviewLoading" body-class="flex items-center" shadow="hover" style="border: none">
+			<el-image :src="getImageSrc()" class="mr-7 rounded-2xl" style="height: 100px; width: 100px; object-fit: contain">
+				<template #error>
+					<div class="mr-3.5 flex items-center justify-center text-5xl" style="height: 100px; width: 100px; background-color: #f5f5f5">
+						<el-icon>
+							<icon-picture />
+						</el-icon>
+					</div>
+				</template>
+			</el-image>
+			<el-col :span="18">
+				<div class="info-container text-lg">
+					<div class="info-column">
+						<div class="font-semibold">
+							电脑编号:
+							<span class="font-medium italic ml-1.5" style="color: #64748b">{{ computerOverview.computerNumber }}</span>
+						</div>
+						<div class="font-semibold">
+							所属店铺:
+							<span class="font-medium italic ml-1.5" style="color: #64748b">{{ computerOverview.platformNumber }}</span>
+						</div>
+						<div class="font-semibold">
+							工位号:
+							<span class="font-medium italic ml-1.5" style="color: #64748b">{{ computerOverview.station }}</span>
+						</div>
+						<div class="font-semibold">
+							IP地址:
+							<span class="font-medium italic ml-1.5" style="color: #64748b">{{ computerOverview.ipaddress }}</span>
+						</div>
+					</div>
+					<div class="info-column">
+						<div class="font-semibold">
+							使用人:
+							<span class="font-medium italic ml-1.5" style="color: #64748b">{{ computerOverview.user }}</span>
+						</div>
+						<div class="font-semibold">
+							电脑类型:
+							<span class="font-medium italic ml-1.5" style="color: #64748b">{{ computerOverview.computerType }}</span>
+						</div>
+						<div class="font-semibold">
+							MAC地址:
+							<span class="font-medium italic ml-1.5" style="color: #64748b">{{ computerOverview.macaddress }}</span>
+						</div>
+					</div>
+				</div>
+			</el-col>
+		</el-card>
+		<!-- table-card -->
+		<el-card body-style="padding-top: 10px" class="mt-2.5" shadow="hover" style="border: none">
+			<vxe-grid :cell-style="cellStyle" :header-cell-style="headerCellStyle" v-bind="gridOptions">
+				<template #toolbar_buttons>
+					<el-button :type="currentView === 'current' ? 'primary' : 'default'" @click="fetchComputerData"> 当前信息 </el-button>
+					<el-button :type="currentView === 'history' ? 'primary' : 'default'" @click="fetchComputerData"> 历史记录 </el-button>
+				</template>
+				<template #pager>
+					<vxe-pager
+						v-model:currentPage="gridOptions.pagerConfig.page"
+						v-model:pageSize="gridOptions.pagerConfig.limit"
+						:total="gridOptions.pagerConfig.total"
+						size="small"
+						@page-change="handlePageChange"
+					>
+					</vxe-pager>
+				</template>
+			</vxe-grid>
+		</el-card>
+	</div>
 </template>
 
-<style scoped lang="scss">
+<style lang="scss" scoped>
 .info-container {
-  display: flex;
-  justify-content: space-between;
+	display: flex;
+	justify-content: space-between;
 }
 
 .info-column {
-  flex: 1;
-  padding: 0 10px;
+	flex: 1;
+	padding: 0 10px;
 }
 
 p {
-  margin: 5px 0;
+	margin: 5px 0;
 }
-</style>
+</style>

+ 112 - 3
src/views/computer-information/components/EditComputerInfo.vue

@@ -1,15 +1,124 @@
-<script setup lang="ts">/**
+<script lang="ts" setup>
+/**
  * @Name: EditComputerInfo.vue
  * @Description: 编辑电脑信息
  * @Author: xinyan
  */
+import { ref } from 'vue';
+import type { UploadInstance, UploadProps, UploadRawFile } from 'element-plus';
+import { genFileId } from 'element-plus';
+import router from '/@/router';
 
+// 图片处理
+const upload = ref<UploadInstance>();
+// 表单数据
+const formData = ref({
+	computerNumber: '',
+	computerType: '',
+	station: '',
+	shop: '',
+	user: '',
+	macaddress: '',
+	ipaddress: '',
+	images: [],
+});
+
+const shopOptions = [
+	{
+		value: 'shop1',
+		label: '店铺一',
+	},
+	{
+		value: 'shop2',
+		label: '店铺二',
+	},
+];
+
+// 表单字段配置
+const formFields = [
+	{ label: '电脑编号:', key: 'computerNumber', required: true },
+	{ label: '电脑类型:', key: 'computerType', required: true },
+	{ label: '工位号:', key: 'station', required: true },
+	{ label: '所属店铺:', key: 'shop', required: true },
+	{ label: '电脑使用人:', key: 'user', required: true },
+	{ label: 'MAC地址:', key: 'macaddress', required: true },
+	{ label: '使用IP地址:', key: 'ipaddress', required: true },
+];
+
+// 超过图片限制时触发的回调
+const handleExceed: UploadProps['onExceed'] = (files) => {
+	upload.value!.clearFiles();
+	const file = files[0] as UploadRawFile;
+	file.uid = genFileId();
+	upload.value!.handleStart(file);
+};
+
+// 保存操作
+const handleSave = () => {
+	console.log(formData);
+};
+
+// 取消操作
+const handleCancel = () => {
+	router.push({
+		path: '/computer',
+	});
+};
 </script>
 
 <template>
+	<el-card class="m-3.5">
+		<div class="font-bold text-xl pb-3.5">电脑信息编辑</div>
+		<el-form :model="formData" class="computer-info-form" label-width="120px">
+			<!-- 使用 v-for 循环渲染表单项 -->
+			<el-form-item v-for="(field, index) in formFields" :key="index" :label="field.label" :required="field.required" size="large">
+				<!-- 判断所属店铺,渲染 el-select -->
+				<el-select v-if="field.key === 'shop'" v-model="formData[field.key]" placeholder="请选择店铺" style="width: 70%">
+					<el-option v-for="shop in shopOptions" :key="shop.value" :label="shop.label" :value="shop.value" />
+				</el-select>
+
+				<!-- 其他字段渲染 el-input -->
+				<el-input v-else v-model="formData[field.key]" style="width: 70%" />
+			</el-form-item>
 
+			<!-- 电脑图片上传 -->
+			<el-form-item :key="images" label="电脑图片:">
+				<el-upload
+					ref="upload"
+					v-model:file-list="formData.images"
+					:auto-upload="false"
+					:limit="1"
+					:on-exceed="handleExceed"
+					action="#"
+					list-type="picture-card"
+				>
+					<el-icon>
+						<Plus />
+					</el-icon>
+				</el-upload>
+			</el-form-item>
+
+			<!-- 按钮组 -->
+			<el-form-item class="button-group">
+				<el-button type="primary" @click="handleSave">保存</el-button>
+				<el-button @click="handleCancel">取消</el-button>
+			</el-form-item>
+		</el-form>
+	</el-card>
 </template>
 
-<style scoped lang="scss">
+<style scoped>
+.computer-info-form {
+	padding: 20px;
+}
+
+.button-group {
+	margin-top: 20px;
+	text-align: center;
+}
 
-</style>
+.computer-info-form :deep(.el-form-item__label) {
+	font-size: 15px;
+	font-weight: bold;
+}
+</style>

+ 39 - 50
src/views/computer-information/components/InfoCard.vue

@@ -8,41 +8,36 @@
 import { ref } from 'vue';
 import { ElIcon, ElMessage } from 'element-plus';
 import { Delete, EditPen, Picture as IconPicture, Search } from '@element-plus/icons-vue';
-import { useResponse } from '/@/utils/useResponse';
 import * as api from '/@/views/computer-information/api';
 import { useRouter } from 'vue-router';
 import { usePagination } from '/@/utils/usePagination';
-import { useElTableData } from '/@/utils/useElTable';
+import { useTableData } from '/@/utils/useTableData';
 
 const router = useRouter();
-const cardItems = ref([]);
 const loading = ref();
-const { tableData, currentPage, pageSize ,total } = usePagination(fetchCardData)
-
-// 分页参数
-// const currentPage = ref(1);
-// const pageSize = ref(10);
-// const total = ref(0);
+const { tableOptions, handlePageChange } = usePagination(fetchCardData);
 
 async function fetchCardData() {
-  const query = {
-    page: currentPage.value,
-    limit: pageSize.value,
-  };
-  await useElTableData(api.getCardData, query, tableData, total, loading)
-	// const res = await useResponse(query, api.getCardData, loading);
-  // tableData.value = res.data;
-  // total.value = res.total;
-  // currentPage.value = res.page;
-  // pageSize.value = res.limit;
+	const query = {
+		page: tableOptions.value.page,
+		limit: tableOptions.value.limit,
+	};
+	await useTableData(api.getCardData, query, tableOptions);
 }
 
+const checkItem = (item) => {
+	router.push({
+		path: '/computer/detail',
+		query: { id: item.id },
+	});
+};
+
 // 编辑和删除的事件处理
 const editItem = (item) => {
 	router.push({
-    path: '/computer/edit',
-    query: { computerNumber: item.computerNumber }
-  })
+		path: '/computer/edit',
+		query: { computerNumber: item.computerNumber },
+	});
 };
 
 const deleteItem = (item) => {
@@ -55,19 +50,20 @@ const deleteItem = (item) => {
 // 处理图片地址
 const getImageUrl = (images) => {
 	// 如果有图片,返回第一个图片的 image_url,否则返回占位图
-	return images.length > 0 ? images[0].image_url : 'https://via.placeholder.com/150';
+	return images.length > 0 ? images[0].image_url : '';
 };
 
 onMounted(() => {
-  fetchCardData();
+	fetchCardData();
 });
 </script>
 
 <template>
-		<!-- 卡片展示区域 -->
+	<!-- 卡片展示区域 -->
+	<el-card shadow="never" style="border: none; min-height: 850px; position: relative;">
 		<div class="card-container">
 			<el-row :gutter="20">
-				<el-col v-for="(item, index) in tableData" :key="index" :span="4" class="my-2.5">
+				<el-col v-for="(item, index) in tableOptions.data" :key="index" :span="4" class="my-2.5">
 					<el-card class="item-card" shadow="hover">
 						<el-image :src="getImageUrl(item.images)" alt="电脑图片" class="card-image">
 							<template #error>
@@ -87,33 +83,26 @@ onMounted(() => {
 							</div>
 						</div>
 						<div class="card-footer">
-              <el-button :icon="Search" circle type="primary" @click="editItem(item)" />
-							<el-button :icon="EditPen" circle type="primary" @click="editItem(item)" />
+							<el-button :icon="Search" circle type="primary" @click="checkItem(item)" />
+							<el-button :icon="EditPen" circle type="warning" @click="editItem(item)" />
 							<el-button :icon="Delete" circle type="danger" @click="deleteItem(item)" />
 						</div>
 					</el-card>
 				</el-col>
 			</el-row>
 		</div>
-    <div class="pagination-container">
-      <!--<el-pagination-->
-      <!--    v-model:current-page="currentPage"-->
-      <!--    :page-size="pageSize"-->
-      <!--    :page-sizes="[10, 25, 50,100,200]"-->
-      <!--    :total="total"-->
-      <!--    background-->
-      <!--    layout="total,sizes,prev, next, jumper"-->
-      <!--    small-->
-      <!--/>-->
-      <el-pagination
-          v-model:current-page="currentPage"
-          v-model:page-size="pageSize"
-          :page-sizes="[10, 20, 30, 50, 100, 200]"
-          :total="total"
-          layout="sizes, prev, pager, next, total"
-          background
-          @change="handlePageChange"/>
-    </div>
+		<div class="pagination-container" style="position: absolute; right: 32px; bottom: 32px;">
+			<el-pagination
+				v-model:current-page="tableOptions.page"
+				v-model:page-size="tableOptions.limit"
+				:page-sizes="[5, 10, 25, 50, 100, 200]"
+				:total="tableOptions.total"
+				background
+				layout="sizes, prev, pager, next, total"
+				@change="handlePageChange"
+			/>
+		</div>
+	</el-card>
 </template>
 
 <style lang="scss" scoped>
@@ -145,8 +134,8 @@ onMounted(() => {
 }
 
 .pagination-container {
-  display: flex;
-  justify-content: flex-end;
-  // margin-bottom: 20px;
+	display: flex;
+	justify-content: flex-end;
+	// margin-bottom: 20px;
 }
 </style>

+ 2 - 5
src/views/computer-information/index.vue

@@ -6,15 +6,12 @@
  */
 
 import InfoCard from '/@/views/computer-information/components/InfoCard.vue';
-
 </script>
 
 <template>
 	<div class="px-5 py-5">
-		<InfoCard />
+			<InfoCard />
 	</div>
 </template>
 
-<style scoped>
-
-</style>
+<style scoped></style>