diff --git a/src/fronted/babel.config.js b/src/fronted/babel.config.js
new file mode 100644
index 0000000..e955840
--- /dev/null
+++ b/src/fronted/babel.config.js
@@ -0,0 +1,5 @@
+module.exports = {
+ presets: [
+ '@vue/cli-plugin-babel/preset'
+ ]
+}
diff --git a/src/fronted/jsconfig.json b/src/fronted/jsconfig.json
new file mode 100644
index 0000000..4aafc5f
--- /dev/null
+++ b/src/fronted/jsconfig.json
@@ -0,0 +1,19 @@
+{
+ "compilerOptions": {
+ "target": "es5",
+ "module": "esnext",
+ "baseUrl": "./",
+ "moduleResolution": "node",
+ "paths": {
+ "@/*": [
+ "src/*"
+ ]
+ },
+ "lib": [
+ "esnext",
+ "dom",
+ "dom.iterable",
+ "scripthost"
+ ]
+ }
+}
diff --git a/src/fronted/package.json b/src/fronted/package.json
new file mode 100644
index 0000000..066e3fb
--- /dev/null
+++ b/src/fronted/package.json
@@ -0,0 +1,49 @@
+{
+ "name": "item-manager-frontend",
+ "version": "0.1.0",
+ "private": true,
+ "scripts": {
+ "serve": "vue-cli-service serve",
+ "build": "vue-cli-service build",
+ "lint": "vue-cli-service lint"
+ },
+ "dependencies": {
+ "@element-plus/icons-vue": "^2.3.2",
+ "axios": "^1.12.2",
+ "core-js": "^3.8.3",
+ "element-plus": "^2.11.2",
+ "eslint-plugin-vue": "^10.4.0",
+ "moment": "^2.30.1",
+ "vue": "^3.2.13",
+ "vue-router": "^4.5.1"
+ },
+ "devDependencies": {
+ "@babel/core": "^7.12.16",
+ "@babel/eslint-parser": "^7.12.16",
+ "@vue/cli-plugin-babel": "~5.0.0",
+ "@vue/cli-plugin-eslint": "~5.0.0",
+ "@vue/cli-service": "~5.0.0"
+ },
+ "eslintConfig": {
+ "root": true,
+ "env": {
+ "node": true
+ },
+ "extends": [
+ "plugin:vue/vue3-essential",
+ "eslint:recommended"
+ ],
+ "parserOptions": {
+ "parser": "@babel/eslint-parser"
+ },
+ "rules": {
+ "vue/multi-word-component-names": 0
+ }
+ },
+ "browserslist": [
+ "> 1%",
+ "last 2 versions",
+ "not dead",
+ "not ie 11"
+ ]
+}
diff --git a/src/fronted/public/favicon.svg b/src/fronted/public/favicon.svg
new file mode 100644
index 0000000..d87ffb9
--- /dev/null
+++ b/src/fronted/public/favicon.svg
@@ -0,0 +1,28 @@
+
diff --git a/src/fronted/public/index.html b/src/fronted/public/index.html
new file mode 100644
index 0000000..a1f30cf
--- /dev/null
+++ b/src/fronted/public/index.html
@@ -0,0 +1,17 @@
+
+
+
+
+
+
+
+ <%= htmlWebpackPlugin.options.title %>
+
+
+
+
+
+
+
diff --git a/src/fronted/src/App.vue b/src/fronted/src/App.vue
new file mode 100644
index 0000000..98240ae
--- /dev/null
+++ b/src/fronted/src/App.vue
@@ -0,0 +1,3 @@
+
+
+
diff --git a/src/fronted/src/components/ConnectionTest.vue b/src/fronted/src/components/ConnectionTest.vue
new file mode 100644
index 0000000..c027500
--- /dev/null
+++ b/src/fronted/src/components/ConnectionTest.vue
@@ -0,0 +1,127 @@
+/* eslint-disable */
+
+
+
+
+ 前后端连接测试
+
+
+
+ 正在测试连接...
+
+
+
+
+ 重新测试
+
+
+
+
+
API数据示例:
+
+ 正常
+ {{ responseTime }}ms
+ JSON
+ 已启用
+
+
+
+
+
+
+
+
+
+
diff --git a/src/fronted/src/components/HelloWorld.vue b/src/fronted/src/components/HelloWorld.vue
new file mode 100644
index 0000000..879051a
--- /dev/null
+++ b/src/fronted/src/components/HelloWorld.vue
@@ -0,0 +1,58 @@
+
+
+
{{ msg }}
+
+ For a guide and recipes on how to configure / customize this project,
+ check out the
+ vue-cli documentation.
+
+
Installed CLI Plugins
+
+
Essential Links
+
+
Ecosystem
+
+
+
+
+
+
+
+
diff --git a/src/fronted/src/main.js b/src/fronted/src/main.js
new file mode 100644
index 0000000..a69cd6c
--- /dev/null
+++ b/src/fronted/src/main.js
@@ -0,0 +1,17 @@
+import { createApp } from 'vue'
+import App from './App.vue'
+import router from './router'
+import ElementPlus from 'element-plus'
+import 'element-plus/dist/index.css'
+import * as ElementPlusIconsVue from '@element-plus/icons-vue'
+
+const app = createApp(App)
+
+// 注册Element Plus图标
+for (const [key, component] of Object.entries(ElementPlusIconsVue)) {
+ app.component(key, component)
+}
+
+app.use(ElementPlus)
+app.use(router)
+app.mount('#app')
diff --git a/src/fronted/src/router/index.js b/src/fronted/src/router/index.js
new file mode 100644
index 0000000..845ca7f
--- /dev/null
+++ b/src/fronted/src/router/index.js
@@ -0,0 +1,42 @@
+import { createRouter, createWebHistory } from 'vue-router'
+import Login from '../views/Login.vue'
+import ItemList from '../views/ItemList.vue'
+import ItemDetail from '../views/ItemDetail.vue'
+import ItemUsage from '../views/ItemUsage.vue'
+import Dashboard from '../views/Dashboard.vue'
+
+const routes = [
+ {
+ path: "/login",
+ name: 'Login',
+ component: Login,
+ },
+ {
+ path: '/',
+ name: 'Dashboard',
+ component: Dashboard
+ },
+ {
+ path: '/items',
+ name: 'ItemList',
+ component: ItemList
+ },
+ {
+ path: '/items/:id',
+ name: 'ItemDetail',
+ component: ItemDetail,
+ props: true
+ },
+ {
+ path: '/usage',
+ name: 'ItemUsage',
+ component: ItemUsage
+ }
+]
+
+const router = createRouter({
+ history: createWebHistory(),
+ routes
+})
+
+export default router
diff --git a/src/fronted/src/services/api.js b/src/fronted/src/services/api.js
new file mode 100644
index 0000000..96eaf2d
--- /dev/null
+++ b/src/fronted/src/services/api.js
@@ -0,0 +1,145 @@
+import axios from 'axios'
+
+const API_BASE_URL = 'http://localhost:8000/api'
+
+const apiClient = axios.create({
+ baseURL: API_BASE_URL,
+ headers: {
+ 'Content-Type': 'application/json'
+ }
+})
+
+// 请求拦截器
+apiClient.interceptors.request.use(
+ config => {
+ console.log('API请求:', config.method?.toUpperCase(), config.url)
+ return config
+ },
+ error => {
+ return Promise.reject(error)
+ }
+)
+
+// 响应拦截器
+apiClient.interceptors.response.use(
+ response => {
+ console.log('API响应:', response.status, response.config.url)
+ return response
+ },
+ error => {
+ console.error('API错误:', error.response?.status, error.response?.data)
+ return Promise.reject(error)
+ }
+)
+
+export const itemService = {
+ // 获取所有物品
+ getAllItems() {
+ return apiClient.get('/items/')
+ },
+
+ // 获取物品详情
+ getItemDetail(id) {
+ return apiClient.get(`/items/${id}/`)
+ },
+
+ // 创建新物品
+ createItem(item) {
+ return apiClient.post('/items/', item)
+ },
+
+ // 更新物品
+ updateItem(id, item) {
+ return apiClient.put(`/items/${id}/`, item)
+ },
+
+ // 删除物品
+ deleteItem(id) {
+ return apiClient.delete(`/items/${id}/`)
+ },
+
+ // 获取可用物品
+ getAvailableItems() {
+ return apiClient.get('/items/available/')
+ },
+
+ // 获取使用中的物品
+ getItemsInUse() {
+ return apiClient.get('/items/in_use/')
+ },
+
+ // 借用物品
+ borrowItem(itemId, borrowData) {
+ return apiClient.post(`/items/${itemId}/borrow/`, borrowData)
+ },
+
+ // 归还物品
+ returnItem(itemId, returnData) {
+ return apiClient.post(`/items/${itemId}/return_item/`, returnData)
+ }
+}
+
+export const usageService = {
+ // 获取所有使用记录
+ getAllUsages() {
+ return apiClient.get('/usages/')
+ },
+
+ // 获取当前使用中的记录
+ getCurrentUsages() {
+ return apiClient.get('/usages/current/')
+ },
+
+ // 根据用户获取使用记录
+ getUserUsages(userId) {
+ return apiClient.get(`/usages/by_user/?user_id=${userId}`)
+ },
+
+ // 创建使用记录
+ createUsage(usage) {
+ return apiClient.post('/usages/', usage)
+ },
+
+ // 更新使用记录
+ updateUsage(id, usage) {
+ return apiClient.put(`/usages/${id}/`, usage)
+ }
+}
+
+export const categoryService = {
+ // 获取所有类别
+ getAllCategories() {
+ return apiClient.get('/categories/')
+ },
+
+ // 创建新类别
+ createCategory(category) {
+ return apiClient.post('/categories/', category)
+ },
+
+ // 更新类别
+ updateCategory(id, category) {
+ return apiClient.put(`/categories/${id}/`, category)
+ },
+
+ // 删除类别
+ deleteCategory(id) {
+ return apiClient.delete(`/categories/${id}/`)
+ }
+}
+
+export const userService = {
+ // 获取所有用户
+ getAllUsers() {
+ return apiClient.get('/users/')
+ }
+}
+
+// 健康检查API
+export const healthService = {
+ checkBackendConnection() {
+ return apiClient.get('/items/')
+ }
+}
+
+export default apiClient
diff --git a/src/fronted/src/views/Dashboard.vue b/src/fronted/src/views/Dashboard.vue
new file mode 100644
index 0000000..33b23eb
--- /dev/null
+++ b/src/fronted/src/views/Dashboard.vue
@@ -0,0 +1,249 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
{{ stats.available }}
+
可用物品
+
+
+
+
+
+
+
+
+
+
+
+
{{ stats.inUse }}
+
使用中
+
+
+
+
+
+
+
+
+
+
+
+
{{ stats.total }}
+
总物品数
+
+
+
+
+
+
+
+
+
+
+
+
{{ stats.maintenance }}
+
维护中
+
+
+
+
+
+
+
+
+
+
+ 当前使用中的物品
+
+
+
+
+
+
+ {{ formatDate(scope.row.start_time) }}
+
+
+
+
+
+
+
+
+
+ 最新添加的物品
+
+
+
+
+
+
+
+ {{ getStatusText(scope.row.status) }}
+
+
+
+
+
+ {{ formatDate(scope.row.created_at) }}
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/src/fronted/src/views/ItemDetail.vue b/src/fronted/src/views/ItemDetail.vue
new file mode 100644
index 0000000..f758061
--- /dev/null
+++ b/src/fronted/src/views/ItemDetail.vue
@@ -0,0 +1,232 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ 取消
+ 保存修改
+
+
+
+
+
+ 当前使用者
+
+
+ {{ item.current_user.username }}
+ {{ item.current_user.first_name }} {{ item.current_user.last_name }}
+ {{ item.current_user.email }}
+
+
+
+
+
+
+ 使用历史
+
+
+
+
+
+ {{ formatDate(scope.row.start_time) }}
+
+
+
+
+ {{ scope.row.end_time ? formatDate(scope.row.end_time) : '使用中' }}
+
+
+
+
+
+
+ {{ scope.row.is_returned ? '已归还' : '使用中' }}
+
+
+
+
+
+ 详情
+
+
+
+
+
+
+
+
+
+
+
+ {{ selectedUsage.user.username }}
+ {{ selectedUsage.purpose }}
+ {{ formatDate(selectedUsage.start_time) }}
+
+ {{ selectedUsage.end_time ? formatDate(selectedUsage.end_time) : '使用中' }}
+
+ {{ selectedUsage.condition_before || '无' }}
+ {{ selectedUsage.condition_after || '无' }}
+ {{ selectedUsage.notes || '无' }}
+
+
+
+
+
+
+
+
+
diff --git a/src/fronted/src/views/ItemList.vue b/src/fronted/src/views/ItemList.vue
new file mode 100644
index 0000000..34af523
--- /dev/null
+++ b/src/fronted/src/views/ItemList.vue
@@ -0,0 +1,382 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ {{ getStatusText(scope.row.status) }}
+
+
+
+
+
+
+ {{ scope.row.current_user.username }}
+
+ -
+
+
+
+
+
+
+ 详情
+
+
+ 借用
+
+
+ 归还
+
+
+ 编辑
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ 取消
+ 保存
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ 取消
+ 确认借用
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ 取消
+ 确认归还
+
+
+
+
+
+
+
+
diff --git a/src/fronted/src/views/ItemUsage.vue b/src/fronted/src/views/ItemUsage.vue
new file mode 100644
index 0000000..87ba291
--- /dev/null
+++ b/src/fronted/src/views/ItemUsage.vue
@@ -0,0 +1,345 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ {{ formatDate(scope.row.start_time) }}
+
+
+
+
+ {{ scope.row.end_time ? formatDate(scope.row.end_time) : '使用中' }}
+
+
+
+
+
+
+ {{ scope.row.is_returned ? '已归还' : '使用中' }}
+
+
+
+
+
+ {{ calculateDuration(scope.row) }}
+
+
+
+
+
+ 详情
+
+
+
+
+
+
+
+
+
+
+
+
+
+ 物品信息
+
+ {{ selectedUsage.item.name }}
+ {{ selectedUsage.item.serial_number }}
+ {{ selectedUsage.item.category }}
+
+
+
+ 使用者信息
+
+ {{ selectedUsage.user.username }}
+
+ {{ selectedUsage.user.first_name }} {{ selectedUsage.user.last_name }}
+
+ {{ selectedUsage.user.email }}
+
+
+
+
+
使用详情
+
+ {{ selectedUsage.purpose }}
+ {{ formatDate(selectedUsage.start_time) }}
+
+ {{ selectedUsage.end_time ? formatDate(selectedUsage.end_time) : '使用中' }}
+
+ {{ calculateDuration(selectedUsage) }}
+ {{ selectedUsage.condition_before || '无记录' }}
+ {{ selectedUsage.condition_after || '无记录' }}
+ {{ selectedUsage.notes || '无' }}
+
+
+ {{ selectedUsage.is_returned ? '已归还' : '使用中' }}
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/src/fronted/src/views/Login.vue b/src/fronted/src/views/Login.vue
new file mode 100644
index 0000000..411356c
--- /dev/null
+++ b/src/fronted/src/views/Login.vue
@@ -0,0 +1,586 @@
+/* eslint-disable */
+
+
+
+
+
+
+
diff --git a/src/fronted/vue.config.js b/src/fronted/vue.config.js
new file mode 100644
index 0000000..5662471
--- /dev/null
+++ b/src/fronted/vue.config.js
@@ -0,0 +1,5 @@
+const { defineConfig } = require('@vue/cli-service')
+module.exports = defineConfig({
+ transpileDependencies: true,
+ lintOnSave:false
+})