v1.0.0: 希姆计算资产管理系统正式版
This commit is contained in:
@@ -0,0 +1,171 @@
|
|||||||
|
# 希姆计算资产管理管理系统
|
||||||
|
|
||||||
|
基于 Django + MySQL 的企业级硬件资产管理系统,支持 Excel 批量导入导出。
|
||||||
|
|
||||||
|
## ✨ 功能特性
|
||||||
|
|
||||||
|
- **仪表盘** — 资产统计总览、分类统计、状态分布、最近变更记录
|
||||||
|
- **资产管理** — 设备增删改查、资产编号/品牌/型号/序列号/资产面值等完整字段
|
||||||
|
- **分类管理** — 自定义设备分类(服务器、网络设备、存储设备等)
|
||||||
|
- **变更追踪** — 资产信息修改自动记录变更历史
|
||||||
|
- **Excel 导入导出** — 批量导入(分类不存在自动创建)、筛选导出、模板下载
|
||||||
|
- **多维度搜索** — 按编号/名称/部门/使用人/位置搜索,按分类/状态/位置筛选
|
||||||
|
- **质保提醒** — 已过保/即将过保状态标识
|
||||||
|
- **用户认证** — 登录/退出,管理员权限控制
|
||||||
|
- **深色主题** — 护眼深色 UI,适合长时间使用
|
||||||
|
|
||||||
|
## 🛠️ 技术栈
|
||||||
|
|
||||||
|
| 组件 | 技术 |
|
||||||
|
|------|------|
|
||||||
|
| 后端 | Django 4.2 |
|
||||||
|
| 数据库 | MySQL / MariaDB |
|
||||||
|
| 前端 | Bootstrap 5 + 自定义深色主题 |
|
||||||
|
| 部署 | Docker Compose / 直接运行 |
|
||||||
|
|
||||||
|
## 📋 资产字段
|
||||||
|
|
||||||
|
| 字段 | 说明 |
|
||||||
|
|------|------|
|
||||||
|
| 资产编号 | 自定义编号,可重复 |
|
||||||
|
| 设备名称 | 设备名称 |
|
||||||
|
| 分类 | 服务器/网络设备/存储设备等(支持自定义) |
|
||||||
|
| 品牌 | 设备品牌 |
|
||||||
|
| 型号 | 设备型号 |
|
||||||
|
| 资产面值 | 资产价值(元) |
|
||||||
|
| 序列号 | 设备序列号 |
|
||||||
|
| 状态 | 在用/闲置/维修中/已报废 |
|
||||||
|
| IP地址 | 管理IP |
|
||||||
|
| BMC地址 | BMC管理地址 |
|
||||||
|
| 设备位置 | 机房/机柜/U位 |
|
||||||
|
| 负责人 | 设备负责人 |
|
||||||
|
| 使用部门 | 使用部门 |
|
||||||
|
| 使用人 | 实际使用人 |
|
||||||
|
| 采购日期 | 采购时间 |
|
||||||
|
| 质保到期 | 质保截止日期 |
|
||||||
|
| 备注 | 补充说明 |
|
||||||
|
|
||||||
|
## 🚀 快速部署
|
||||||
|
|
||||||
|
### 方式一:Docker Compose(推荐)
|
||||||
|
|
||||||
|
```bash
|
||||||
|
# 克隆仓库
|
||||||
|
git clone ssh://git@git.cnbugs.com:10022/cnbugs/asset-management.git
|
||||||
|
cd asset-management
|
||||||
|
|
||||||
|
# 启动服务
|
||||||
|
docker-compose up -d
|
||||||
|
|
||||||
|
# 访问系统
|
||||||
|
# http://<服务器IP>:8010
|
||||||
|
# 默认账号: admin / admin123
|
||||||
|
```
|
||||||
|
|
||||||
|
### 方式二:直接运行
|
||||||
|
|
||||||
|
```bash
|
||||||
|
# 克隆仓库
|
||||||
|
git clone ssh://git@git.cnbugs.com:10022/cnbugs/asset-management.git
|
||||||
|
cd asset-management
|
||||||
|
|
||||||
|
# 创建虚拟环境
|
||||||
|
python3 -m venv venv
|
||||||
|
source venv/bin/activate
|
||||||
|
|
||||||
|
# 安装依赖
|
||||||
|
pip install -r requirements.txt
|
||||||
|
|
||||||
|
# 配置数据库(修改 config/settings.py 中的 DATABASES)
|
||||||
|
# 创建 MySQL 数据库: CREATE DATABASE asset_management CHARACTER SET utf8mb4;
|
||||||
|
|
||||||
|
# 初始化
|
||||||
|
python manage.py migrate
|
||||||
|
python manage.py createsuperuser
|
||||||
|
|
||||||
|
# 启动
|
||||||
|
python manage.py runserver 0.0.0.0:8010
|
||||||
|
```
|
||||||
|
|
||||||
|
## ⚙️ 配置说明
|
||||||
|
|
||||||
|
### 数据库配置
|
||||||
|
|
||||||
|
编辑 `config/settings.py` 中的 `DATABASES`:
|
||||||
|
|
||||||
|
```python
|
||||||
|
DATABASES = {
|
||||||
|
'default': {
|
||||||
|
'ENGINE': 'django.db.backends.mysql',
|
||||||
|
'NAME': 'asset_management',
|
||||||
|
'USER': 'root',
|
||||||
|
'PASSWORD': 'password123',
|
||||||
|
'HOST': 'localhost',
|
||||||
|
'PORT': '3306',
|
||||||
|
}
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
### Docker 环境变量
|
||||||
|
|
||||||
|
在 `docker-compose.yml` 中配置:
|
||||||
|
|
||||||
|
| 变量 | 默认值 | 说明 |
|
||||||
|
|------|--------|------|
|
||||||
|
| MYSQL_HOST | db | MySQL 主机 |
|
||||||
|
| MYSQL_PORT | 3306 | MySQL 端口 |
|
||||||
|
| MYSQL_USER | root | MySQL 用户 |
|
||||||
|
| MYSQL_PASSWORD | password123 | MySQL 密码 |
|
||||||
|
| MYSQL_DATABASE | asset_management | 数据库名 |
|
||||||
|
| DJANGO_DEBUG | False | 调试模式 |
|
||||||
|
| DJANGO_SECRET_KEY | your-secret-key... | Django 密钥 |
|
||||||
|
|
||||||
|
## 📊 Excel 导入格式
|
||||||
|
|
||||||
|
| 资产编号 | 设备名称 | 分类 | 品牌 | 型号 | 资产面值 | 序列号 | 状态 | IP地址 | BMC地址 | 设备位置 | 负责人 | 使用部门 | 使用人 | 采购日期 | 质保到期 | 备注 |
|
||||||
|
|----------|---------|------|------|------|---------|--------|------|--------|---------|---------|--------|---------|--------|---------|---------|------|
|
||||||
|
|
||||||
|
- 分类不存在时自动创建
|
||||||
|
- 资产编号允许重复
|
||||||
|
- 日期格式:YYYY-MM-DD
|
||||||
|
- 状态可选:在用、闲置、维修中、已报废
|
||||||
|
|
||||||
|
## 📁 项目结构
|
||||||
|
|
||||||
|
```
|
||||||
|
asset-management/
|
||||||
|
├── assetapp/ # 主应用
|
||||||
|
│ ├── models.py # 数据模型
|
||||||
|
│ ├── views.py # 视图逻辑
|
||||||
|
│ ├── forms.py # 表单定义
|
||||||
|
│ ├── excel_utils.py # Excel 导入导出工具
|
||||||
|
│ ├── urls.py # URL 路由
|
||||||
|
│ ├── management/commands/ # 管理命令
|
||||||
|
│ ├── migrations/ # 数据库迁移
|
||||||
|
│ └── templatetags/ # 自定义模板标签
|
||||||
|
├── config/ # Django 配置
|
||||||
|
│ ├── settings.py
|
||||||
|
│ ├── urls.py
|
||||||
|
│ └── wsgi.py
|
||||||
|
├── templates/assetapp/ # HTML 模板
|
||||||
|
├── static/css/ # 静态资源
|
||||||
|
├── docker-compose.yml # Docker 编排
|
||||||
|
├── Dockerfile # 容器构建
|
||||||
|
├── entrypoint.sh # 启动脚本
|
||||||
|
├── requirements.txt # Python 依赖
|
||||||
|
└── manage.py # Django 入口
|
||||||
|
```
|
||||||
|
|
||||||
|
## 📝 版本历史
|
||||||
|
|
||||||
|
### v1.0.0
|
||||||
|
|
||||||
|
- 资产增删改查
|
||||||
|
- 仪表盘统计
|
||||||
|
- 分类管理
|
||||||
|
- 变更追踪
|
||||||
|
- Excel 导入导出
|
||||||
|
- 多维度搜索筛选
|
||||||
|
- 质保到期提醒
|
||||||
|
- 深色主题
|
||||||
|
- Docker 部署支持
|
||||||
+17
-8
@@ -13,6 +13,7 @@ EXPORT_COLUMNS = [
|
|||||||
('category', '设备分类', 12),
|
('category', '设备分类', 12),
|
||||||
('brand', '品牌', 12),
|
('brand', '品牌', 12),
|
||||||
('model', '型号', 20),
|
('model', '型号', 20),
|
||||||
|
('asset_value', '资产面值', 12),
|
||||||
('serial_number', '序列号', 25),
|
('serial_number', '序列号', 25),
|
||||||
('location', '设备位置', 20),
|
('location', '设备位置', 20),
|
||||||
('cabinet', '机柜', 10),
|
('cabinet', '机柜', 10),
|
||||||
@@ -23,6 +24,8 @@ EXPORT_COLUMNS = [
|
|||||||
('warranty_expire', '质保到期', 12),
|
('warranty_expire', '质保到期', 12),
|
||||||
('supplier', '供应商', 15),
|
('supplier', '供应商', 15),
|
||||||
('responsible_person', '负责人', 10),
|
('responsible_person', '负责人', 10),
|
||||||
|
('department', '使用部门', 15),
|
||||||
|
('user', '使用人', 10),
|
||||||
('status', '状态', 8),
|
('status', '状态', 8),
|
||||||
('remark', '备注', 30),
|
('remark', '备注', 30),
|
||||||
]
|
]
|
||||||
@@ -100,8 +103,8 @@ def generate_import_template():
|
|||||||
# 示例数据行
|
# 示例数据行
|
||||||
example_data = [
|
example_data = [
|
||||||
'IT-2024-0001', '测试服务器', '服务器', 'Dell', 'PowerEdge R740',
|
'IT-2024-0001', '测试服务器', '服务器', 'Dell', 'PowerEdge R740',
|
||||||
'ABC123456', '3楼机房A区', 'A01', 'U10-U15', '192.168.1.200',
|
'50000.00', 'ABC123456', '3楼机房A区', 'A01', 'U10-U15', '192.168.1.200',
|
||||||
'192.168.1.100', '2024-01-15', '2027-01-15', '戴尔科技', '张三', '在用', '测试备注'
|
'192.168.1.100', '2024-01-15', '2027-01-15', '戴尔科技', '张三', '研发部', '李四', '在用', '测试备注'
|
||||||
]
|
]
|
||||||
for col_idx, value in enumerate(example_data, 1):
|
for col_idx, value in enumerate(example_data, 1):
|
||||||
cell = ws.cell(row=2, column=col_idx, value=value)
|
cell = ws.cell(row=2, column=col_idx, value=value)
|
||||||
@@ -147,12 +150,6 @@ def import_assets_from_excel(ws, category_map, operator=None):
|
|||||||
results['errors'].append(f'第{row_idx}行: 缺少资产编号')
|
results['errors'].append(f'第{row_idx}行: 缺少资产编号')
|
||||||
continue
|
continue
|
||||||
|
|
||||||
# 检查重复
|
|
||||||
if Asset.objects.filter(asset_number=asset_number).exists():
|
|
||||||
results['skipped'] += 1
|
|
||||||
results['errors'].append(f'第{row_idx}行: 资产编号 {asset_number} 已存在')
|
|
||||||
continue
|
|
||||||
|
|
||||||
# 处理分类 - 不存在则自动创建
|
# 处理分类 - 不存在则自动创建
|
||||||
category_name = data.get('category', '').strip()
|
category_name = data.get('category', '').strip()
|
||||||
category = category_map.get(category_name)
|
category = category_map.get(category_name)
|
||||||
@@ -187,12 +184,22 @@ def import_assets_from_excel(ws, category_map, operator=None):
|
|||||||
bmc_address = data.get('bmc_address') or None
|
bmc_address = data.get('bmc_address') or None
|
||||||
ip_address = data.get('ip_address') or None
|
ip_address = data.get('ip_address') or None
|
||||||
|
|
||||||
|
# 处理资产面值
|
||||||
|
from decimal import Decimal, InvalidOperation
|
||||||
|
asset_value = None
|
||||||
|
if data.get('asset_value'):
|
||||||
|
try:
|
||||||
|
asset_value = Decimal(str(data['asset_value']).replace(',', ''))
|
||||||
|
except (InvalidOperation, ValueError):
|
||||||
|
pass
|
||||||
|
|
||||||
asset = Asset.objects.create(
|
asset = Asset.objects.create(
|
||||||
asset_number=asset_number,
|
asset_number=asset_number,
|
||||||
name=data.get('name', ''),
|
name=data.get('name', ''),
|
||||||
category=category,
|
category=category,
|
||||||
brand=data.get('brand', ''),
|
brand=data.get('brand', ''),
|
||||||
model=data.get('model', ''),
|
model=data.get('model', ''),
|
||||||
|
asset_value=asset_value,
|
||||||
serial_number=data.get('serial_number', ''),
|
serial_number=data.get('serial_number', ''),
|
||||||
location=data.get('location', ''),
|
location=data.get('location', ''),
|
||||||
cabinet=data.get('cabinet', ''),
|
cabinet=data.get('cabinet', ''),
|
||||||
@@ -203,6 +210,8 @@ def import_assets_from_excel(ws, category_map, operator=None):
|
|||||||
warranty_expire=warranty_expire,
|
warranty_expire=warranty_expire,
|
||||||
supplier=data.get('supplier', ''),
|
supplier=data.get('supplier', ''),
|
||||||
responsible_person=data.get('responsible_person', ''),
|
responsible_person=data.get('responsible_person', ''),
|
||||||
|
department=data.get('department', ''),
|
||||||
|
user=data.get('user', ''),
|
||||||
status=status,
|
status=status,
|
||||||
remark=data.get('remark', ''),
|
remark=data.get('remark', ''),
|
||||||
created_by=operator,
|
created_by=operator,
|
||||||
|
|||||||
+2
-2
@@ -6,10 +6,10 @@ class AssetForm(forms.ModelForm):
|
|||||||
class Meta:
|
class Meta:
|
||||||
model = Asset
|
model = Asset
|
||||||
fields = [
|
fields = [
|
||||||
'asset_number', 'name', 'category', 'brand', 'model', 'serial_number',
|
'asset_number', 'name', 'category', 'brand', 'model', 'asset_value', 'serial_number',
|
||||||
'location', 'cabinet', 'cabinet_position', 'bmc_address', 'ip_address',
|
'location', 'cabinet', 'cabinet_position', 'bmc_address', 'ip_address',
|
||||||
'purchase_date', 'warranty_expire', 'supplier',
|
'purchase_date', 'warranty_expire', 'supplier',
|
||||||
'responsible_person', 'status', 'remark',
|
'responsible_person', 'department', 'user', 'status', 'remark',
|
||||||
]
|
]
|
||||||
widgets = {
|
widgets = {
|
||||||
'purchase_date': forms.DateInput(attrs={'type': 'date'}),
|
'purchase_date': forms.DateInput(attrs={'type': 'date'}),
|
||||||
|
|||||||
@@ -0,0 +1,18 @@
|
|||||||
|
# Generated by Django 5.2.13 on 2026-04-25 00:10
|
||||||
|
|
||||||
|
from django.db import migrations, models
|
||||||
|
|
||||||
|
|
||||||
|
class Migration(migrations.Migration):
|
||||||
|
|
||||||
|
dependencies = [
|
||||||
|
('assetapp', '0002_asset_bmc_address'),
|
||||||
|
]
|
||||||
|
|
||||||
|
operations = [
|
||||||
|
migrations.AlterField(
|
||||||
|
model_name='asset',
|
||||||
|
name='asset_number',
|
||||||
|
field=models.CharField(db_index=True, max_length=50, verbose_name='资产编号'),
|
||||||
|
),
|
||||||
|
]
|
||||||
@@ -0,0 +1,23 @@
|
|||||||
|
# Generated by Django 5.2.13 on 2026-04-25 00:21
|
||||||
|
|
||||||
|
from django.db import migrations, models
|
||||||
|
|
||||||
|
|
||||||
|
class Migration(migrations.Migration):
|
||||||
|
|
||||||
|
dependencies = [
|
||||||
|
('assetapp', '0003_alter_asset_asset_number'),
|
||||||
|
]
|
||||||
|
|
||||||
|
operations = [
|
||||||
|
migrations.AddField(
|
||||||
|
model_name='asset',
|
||||||
|
name='department',
|
||||||
|
field=models.CharField(blank=True, default='', max_length=100, verbose_name='使用部门'),
|
||||||
|
),
|
||||||
|
migrations.AddField(
|
||||||
|
model_name='asset',
|
||||||
|
name='user',
|
||||||
|
field=models.CharField(blank=True, default='', max_length=50, verbose_name='使用人'),
|
||||||
|
),
|
||||||
|
]
|
||||||
@@ -0,0 +1,18 @@
|
|||||||
|
# Generated by Django 5.2.13 on 2026-04-25 00:25
|
||||||
|
|
||||||
|
from django.db import migrations, models
|
||||||
|
|
||||||
|
|
||||||
|
class Migration(migrations.Migration):
|
||||||
|
|
||||||
|
dependencies = [
|
||||||
|
('assetapp', '0004_asset_department_asset_user'),
|
||||||
|
]
|
||||||
|
|
||||||
|
operations = [
|
||||||
|
migrations.AddField(
|
||||||
|
model_name='asset',
|
||||||
|
name='asset_value',
|
||||||
|
field=models.DecimalField(blank=True, decimal_places=2, max_digits=12, null=True, verbose_name='资产面值'),
|
||||||
|
),
|
||||||
|
]
|
||||||
+4
-1
@@ -29,13 +29,14 @@ class Asset(models.Model):
|
|||||||
]
|
]
|
||||||
|
|
||||||
# 基本信息
|
# 基本信息
|
||||||
asset_number = models.CharField('资产编号', max_length=50, unique=True, db_index=True)
|
asset_number = models.CharField('资产编号', max_length=50, db_index=True)
|
||||||
name = models.CharField('设备名称', max_length=100)
|
name = models.CharField('设备名称', max_length=100)
|
||||||
category = models.ForeignKey(Category, on_delete=models.PROTECT, verbose_name='设备分类', related_name='assets')
|
category = models.ForeignKey(Category, on_delete=models.PROTECT, verbose_name='设备分类', related_name='assets')
|
||||||
|
|
||||||
# 硬件信息
|
# 硬件信息
|
||||||
brand = models.CharField('品牌', max_length=50, blank=True, default='')
|
brand = models.CharField('品牌', max_length=50, blank=True, default='')
|
||||||
model = models.CharField('型号', max_length=100, blank=True, default='')
|
model = models.CharField('型号', max_length=100, blank=True, default='')
|
||||||
|
asset_value = models.DecimalField('资产面值', max_digits=12, decimal_places=2, blank=True, null=True)
|
||||||
serial_number = models.CharField('序列号', max_length=100, blank=True, default='', db_index=True)
|
serial_number = models.CharField('序列号', max_length=100, blank=True, default='', db_index=True)
|
||||||
|
|
||||||
# 位置信息
|
# 位置信息
|
||||||
@@ -54,6 +55,8 @@ class Asset(models.Model):
|
|||||||
|
|
||||||
# 管理信息
|
# 管理信息
|
||||||
responsible_person = models.CharField('负责人', max_length=50, blank=True, default='')
|
responsible_person = models.CharField('负责人', max_length=50, blank=True, default='')
|
||||||
|
department = models.CharField('使用部门', max_length=100, blank=True, default='')
|
||||||
|
user = models.CharField('使用人', max_length=50, blank=True, default='')
|
||||||
status = models.CharField('状态', max_length=20, choices=STATUS_CHOICES, default='in_use')
|
status = models.CharField('状态', max_length=20, choices=STATUS_CHOICES, default='in_use')
|
||||||
remark = models.TextField('备注', blank=True, default='')
|
remark = models.TextField('备注', blank=True, default='')
|
||||||
|
|
||||||
|
|||||||
+5
-3
@@ -99,7 +99,9 @@ def asset_list(request):
|
|||||||
Q(brand__icontains=search) |
|
Q(brand__icontains=search) |
|
||||||
Q(model__icontains=search) |
|
Q(model__icontains=search) |
|
||||||
Q(location__icontains=search) |
|
Q(location__icontains=search) |
|
||||||
Q(responsible_person__icontains=search)
|
Q(responsible_person__icontains=search) |
|
||||||
|
Q(department__icontains=search) |
|
||||||
|
Q(user__icontains=search)
|
||||||
)
|
)
|
||||||
|
|
||||||
# 筛选
|
# 筛选
|
||||||
@@ -116,8 +118,8 @@ def asset_list(request):
|
|||||||
queryset = queryset.filter(location__icontains=location)
|
queryset = queryset.filter(location__icontains=location)
|
||||||
|
|
||||||
# 排序
|
# 排序
|
||||||
sort = request.GET.get('sort', '-created_at')
|
sort = request.GET.get('sort', 'id')
|
||||||
valid_sorts = ['asset_number', '-asset_number', 'name', '-name',
|
valid_sorts = ['id', '-id', 'asset_number', '-asset_number', 'name', '-name',
|
||||||
'created_at', '-created_at', 'updated_at', '-updated_at',
|
'created_at', '-created_at', 'updated_at', '-updated_at',
|
||||||
'purchase_date', '-purchase_date']
|
'purchase_date', '-purchase_date']
|
||||||
if sort not in valid_sorts:
|
if sort not in valid_sorts:
|
||||||
|
|||||||
@@ -39,6 +39,7 @@
|
|||||||
<tr><td class="text-muted">设备分类</td><td><span class="badge bg-secondary">{{ asset.category.name }}</span></td></tr>
|
<tr><td class="text-muted">设备分类</td><td><span class="badge bg-secondary">{{ asset.category.name }}</span></td></tr>
|
||||||
<tr><td class="text-muted">品牌</td><td>{{ asset.brand|default:"-" }}</td></tr>
|
<tr><td class="text-muted">品牌</td><td>{{ asset.brand|default:"-" }}</td></tr>
|
||||||
<tr><td class="text-muted">型号</td><td>{{ asset.model|default:"-" }}</td></tr>
|
<tr><td class="text-muted">型号</td><td>{{ asset.model|default:"-" }}</td></tr>
|
||||||
|
<tr><td class="text-muted">资产面值</td><td>{% if asset.asset_value %}¥{{ asset.asset_value }}{% else %}-{% endif %}</td></tr>
|
||||||
<tr><td class="text-muted">序列号</td><td><code>{{ asset.serial_number|default:"-" }}</code></td></tr>
|
<tr><td class="text-muted">序列号</td><td><code>{{ asset.serial_number|default:"-" }}</code></td></tr>
|
||||||
</table>
|
</table>
|
||||||
</div>
|
</div>
|
||||||
@@ -57,6 +58,8 @@
|
|||||||
<tr><td class="text-muted">BMC地址</td><td><code>{{ asset.bmc_address|default:"-" }}</code></td></tr>
|
<tr><td class="text-muted">BMC地址</td><td><code>{{ asset.bmc_address|default:"-" }}</code></td></tr>
|
||||||
<tr><td class="text-muted">IP地址</td><td><code>{{ asset.ip_address|default:"-" }}</code></td></tr>
|
<tr><td class="text-muted">IP地址</td><td><code>{{ asset.ip_address|default:"-" }}</code></td></tr>
|
||||||
<tr><td class="text-muted">负责人</td><td>{{ asset.responsible_person|default:"-" }}</td></tr>
|
<tr><td class="text-muted">负责人</td><td>{{ asset.responsible_person|default:"-" }}</td></tr>
|
||||||
|
<tr><td class="text-muted">使用部门</td><td>{{ asset.department|default:"-" }}</td></tr>
|
||||||
|
<tr><td class="text-muted">使用人</td><td>{{ asset.user|default:"-" }}</td></tr>
|
||||||
<tr><td class="text-muted">状态</td>
|
<tr><td class="text-muted">状态</td>
|
||||||
<td><span class="badge
|
<td><span class="badge
|
||||||
{% if asset.status == 'in_use' %}bg-success
|
{% if asset.status == 'in_use' %}bg-success
|
||||||
|
|||||||
@@ -89,6 +89,14 @@
|
|||||||
<label class="form-label text-muted">{{ form.responsible_person.label }}</label>
|
<label class="form-label text-muted">{{ form.responsible_person.label }}</label>
|
||||||
{{ form.responsible_person }}
|
{{ form.responsible_person }}
|
||||||
</div>
|
</div>
|
||||||
|
<div class="mb-3">
|
||||||
|
<label class="form-label text-muted">{{ form.department.label }}</label>
|
||||||
|
{{ form.department }}
|
||||||
|
</div>
|
||||||
|
<div class="mb-3">
|
||||||
|
<label class="form-label text-muted">{{ form.user.label }}</label>
|
||||||
|
{{ form.user }}
|
||||||
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|||||||
@@ -25,7 +25,7 @@
|
|||||||
<div class="col-md-4">
|
<div class="col-md-4">
|
||||||
<label class="form-label text-muted small">搜索</label>
|
<label class="form-label text-muted small">搜索</label>
|
||||||
<input type="text" name="search" class="form-control form-control-sm"
|
<input type="text" name="search" class="form-control form-control-sm"
|
||||||
placeholder="编号/名称/序列号/IP/品牌/型号/位置/负责人" value="{{ search }}">
|
placeholder="编号/名称/序列号/IP/品牌/型号/位置/负责人/部门/使用人" value="{{ search }}">
|
||||||
</div>
|
</div>
|
||||||
<div class="col-md-2">
|
<div class="col-md-2">
|
||||||
<label class="form-label text-muted small">分类</label>
|
<label class="form-label text-muted small">分类</label>
|
||||||
@@ -73,10 +73,13 @@
|
|||||||
<th>设备名称</th>
|
<th>设备名称</th>
|
||||||
<th>分类</th>
|
<th>分类</th>
|
||||||
<th>品牌/型号</th>
|
<th>品牌/型号</th>
|
||||||
|
<th>资产面值</th>
|
||||||
<th>位置</th>
|
<th>位置</th>
|
||||||
<th>BMC地址</th>
|
<th>BMC地址</th>
|
||||||
<th>IP地址</th>
|
<th>IP地址</th>
|
||||||
<th>负责人</th>
|
<th>负责人</th>
|
||||||
|
<th>使用部门</th>
|
||||||
|
<th>使用人</th>
|
||||||
<th>状态</th>
|
<th>状态</th>
|
||||||
<th>操作</th>
|
<th>操作</th>
|
||||||
</tr>
|
</tr>
|
||||||
@@ -88,6 +91,7 @@
|
|||||||
<td>{{ asset.name }}</td>
|
<td>{{ asset.name }}</td>
|
||||||
<td><span class="badge bg-secondary">{{ asset.category.name }}</span></td>
|
<td><span class="badge bg-secondary">{{ asset.category.name }}</span></td>
|
||||||
<td>{{ asset.brand }} {% if asset.model %}{{ asset.model }}{% endif %}</td>
|
<td>{{ asset.brand }} {% if asset.model %}{{ asset.model }}{% endif %}</td>
|
||||||
|
<td>{% if asset.asset_value %}¥{{ asset.asset_value }}{% else %}-{% endif %}</td>
|
||||||
<td>
|
<td>
|
||||||
{{ asset.location }}
|
{{ asset.location }}
|
||||||
{% if asset.cabinet %}<small class="text-muted"> {{ asset.cabinet }}{% if asset.cabinet_position %}/{{ asset.cabinet_position }}{% endif %}</small>{% endif %}
|
{% if asset.cabinet %}<small class="text-muted"> {{ asset.cabinet }}{% if asset.cabinet_position %}/{{ asset.cabinet_position }}{% endif %}</small>{% endif %}
|
||||||
@@ -95,6 +99,8 @@
|
|||||||
<td><code>{{ asset.bmc_address|default:"-" }}</code></td>
|
<td><code>{{ asset.bmc_address|default:"-" }}</code></td>
|
||||||
<td><code>{{ asset.ip_address|default:"-" }}</code></td>
|
<td><code>{{ asset.ip_address|default:"-" }}</code></td>
|
||||||
<td>{{ asset.responsible_person|default:"-" }}</td>
|
<td>{{ asset.responsible_person|default:"-" }}</td>
|
||||||
|
<td>{{ asset.department|default:"-" }}</td>
|
||||||
|
<td>{{ asset.user|default:"-" }}</td>
|
||||||
<td>
|
<td>
|
||||||
<span class="badge
|
<span class="badge
|
||||||
{% if asset.status == 'in_use' %}bg-success
|
{% if asset.status == 'in_use' %}bg-success
|
||||||
@@ -130,19 +136,19 @@
|
|||||||
<nav class="mt-3">
|
<nav class="mt-3">
|
||||||
<ul class="pagination pagination-sm justify-content-center">
|
<ul class="pagination pagination-sm justify-content-center">
|
||||||
{% if page_obj.has_previous %}
|
{% if page_obj.has_previous %}
|
||||||
<li class="page-item"><a class="page-link" href="?page={{ page_obj.previous_page_number }}&search={{ search }}&category={{ current_category }}&status={{ current_status }}&location={{ current_location }}"><i class="bi bi-chevron-left"></i></a></li>
|
<li class="page-item"><a class="page-link" href="?page={{ page_obj.previous_page_number }}{% if search %}&search={{ search }}{% endif %}{% if current_category %}&category={{ current_category }}{% endif %}{% if current_status %}&status={{ current_status }}{% endif %}{% if current_location %}&location={{ current_location }}{% endif %}"><i class="bi bi-chevron-left"></i></a></li>
|
||||||
{% endif %}
|
{% endif %}
|
||||||
|
|
||||||
{% for num in page_obj.paginator.page_range %}
|
{% for num in page_obj.paginator.page_range %}
|
||||||
{% if page_obj.number == num %}
|
{% if page_obj.number == num %}
|
||||||
<li class="page-item active"><span class="page-link">{{ num }}</span></li>
|
<li class="page-item active"><span class="page-link">{{ num }}</span></li>
|
||||||
{% elif num > page_obj.number|add:'-3' and num < page_obj.number|add:'3' %}
|
{% elif num > page_obj.number|add:'-3' and num < page_obj.number|add:'3' %}
|
||||||
<li class="page-item"><a class="page-link" href="?page={{ num }}&search={{ search }}&category={{ current_category }}&status={{ current_status }}&location={{ current_location }}">{{ num }}</a></li>
|
<li class="page-item"><a class="page-link" href="?page={{ num }}{% if search %}&search={{ search }}{% endif %}{% if current_category %}&category={{ current_category }}{% endif %}{% if current_status %}&status={{ current_status }}{% endif %}{% if current_location %}&location={{ current_location }}{% endif %}">{{ num }}</a></li>
|
||||||
{% endif %}
|
{% endif %}
|
||||||
{% endfor %}
|
{% endfor %}
|
||||||
|
|
||||||
{% if page_obj.has_next %}
|
{% if page_obj.has_next %}
|
||||||
<li class="page-item"><a class="page-link" href="?page={{ page_obj.next_page_number }}&search={{ search }}&category={{ current_category }}&status={{ current_status }}&location={{ current_location }}"><i class="bi bi-chevron-right"></i></a></li>
|
<li class="page-item"><a class="page-link" href="?page={{ page_obj.next_page_number }}{% if search %}&search={{ search }}{% endif %}{% if current_category %}&category={{ current_category }}{% endif %}{% if current_status %}&status={{ current_status }}{% endif %}{% if current_location %}&location={{ current_location }}{% endif %}"><i class="bi bi-chevron-right"></i></a></li>
|
||||||
{% endif %}
|
{% endif %}
|
||||||
</ul>
|
</ul>
|
||||||
</nav>
|
</nav>
|
||||||
|
|||||||
Reference in New Issue
Block a user