Update 2026-06-10 11:45:26
This commit is contained in:
+92
@@ -0,0 +1,92 @@
|
|||||||
|
# --- Python ---
|
||||||
|
__pycache__/
|
||||||
|
*.py[cod]
|
||||||
|
*$py.class
|
||||||
|
*.so
|
||||||
|
.Python
|
||||||
|
*.egg
|
||||||
|
*.egg-info/
|
||||||
|
.eggs/
|
||||||
|
dist/
|
||||||
|
build/
|
||||||
|
pip-log.txt
|
||||||
|
pip-delete-this-directory.txt
|
||||||
|
|
||||||
|
# Virtual environments
|
||||||
|
.venv/
|
||||||
|
venv/
|
||||||
|
ENV/
|
||||||
|
env/
|
||||||
|
.python-version
|
||||||
|
|
||||||
|
# --- Django ---
|
||||||
|
*.log
|
||||||
|
local_settings.py
|
||||||
|
db.sqlite3
|
||||||
|
db.sqlite3-journal
|
||||||
|
|
||||||
|
# Collected static (if STATIC_ROOT differs from source)
|
||||||
|
staticfiles/
|
||||||
|
collected_static/
|
||||||
|
|
||||||
|
# Compiled translations (generate via compilemessages)
|
||||||
|
*.mo
|
||||||
|
|
||||||
|
# --- Environment & secrets ---
|
||||||
|
.env
|
||||||
|
.env.*
|
||||||
|
!.env.example
|
||||||
|
*.pem
|
||||||
|
*.key
|
||||||
|
|
||||||
|
# --- IDE / Editor ---
|
||||||
|
.idea/
|
||||||
|
.vscode/
|
||||||
|
*.sublime-project
|
||||||
|
*.sublime-workspace
|
||||||
|
*.swp
|
||||||
|
*.swo
|
||||||
|
*~
|
||||||
|
|
||||||
|
# --- OS ---
|
||||||
|
.DS_Store
|
||||||
|
.DS_Store?
|
||||||
|
Thumbs.db
|
||||||
|
ehthumbs.db
|
||||||
|
desktop.ini
|
||||||
|
|
||||||
|
# --- Cursor / local workflow ---
|
||||||
|
.cursor/
|
||||||
|
.work/
|
||||||
|
|
||||||
|
# --- Test & coverage ---
|
||||||
|
.coverage
|
||||||
|
.coverage.*
|
||||||
|
htmlcov/
|
||||||
|
.tox/
|
||||||
|
.nox/
|
||||||
|
.pytest_cache/
|
||||||
|
.mypy_cache/
|
||||||
|
.dmypy.json
|
||||||
|
dmypy.json
|
||||||
|
|
||||||
|
# --- Docker (local overrides & volumes) ---
|
||||||
|
docker-compose.override.yml
|
||||||
|
docker-compose.local.yml
|
||||||
|
*.volume/
|
||||||
|
|
||||||
|
# --- User uploads (MEDIA_ROOT) ---
|
||||||
|
# Keep template docs under upload/doc/
|
||||||
|
upload/data/*
|
||||||
|
!upload/data/.gitkeep
|
||||||
|
upload/inventory/*
|
||||||
|
!upload/inventory/.gitkeep
|
||||||
|
upload/project/*
|
||||||
|
!upload/project/.gitkeep
|
||||||
|
upload/offer sheet/*
|
||||||
|
!upload/offer sheet/.gitkeep
|
||||||
|
|
||||||
|
# --- Misc ---
|
||||||
|
*.bak
|
||||||
|
*.tmp
|
||||||
|
*.orig
|
||||||
+3
-3
@@ -2,7 +2,7 @@
|
|||||||
|
|
||||||
## 当前进度
|
## 当前进度
|
||||||
|
|
||||||
- **当前步骤**:步骤 10
|
- **当前步骤**:步骤 11
|
||||||
- **状态**:success
|
- **状态**:success
|
||||||
- **开始时间**:2026-6-10 09:51:31
|
- **开始时间**:2026-6-10 09:51:31
|
||||||
- **完成时间**:
|
- **完成时间**:
|
||||||
@@ -71,9 +71,9 @@
|
|||||||
- **说明**:健康验证通过。Web 服务(6010)已成功启动并可以正常访问登录页面。
|
- **说明**:健康验证通过。Web 服务(6010)已成功启动并可以正常访问登录页面。
|
||||||
|
|
||||||
### 步骤 11:提交
|
### 步骤 11:提交
|
||||||
- **状态**:⏭️ 未开始
|
- **状态**:success
|
||||||
- **完成时间**:
|
- **完成时间**:
|
||||||
- **说明**:
|
- **说明**:所有步骤已完成。项目已成功部署并提交。
|
||||||
|
|
||||||
## 错误记录
|
## 错误记录
|
||||||
|
|
||||||
|
|||||||
@@ -0,0 +1,45 @@
|
|||||||
|
-- 销售订单示例数据(依赖 basedata_partner / basedata_material 等基础数据)
|
||||||
|
-- 导入: mysql -uroot -proot mis < Install/SQL/sale_order_sample.sql
|
||||||
|
|
||||||
|
SET NAMES utf8mb4;
|
||||||
|
|
||||||
|
INSERT INTO `sale_saleorder`
|
||||||
|
(`id`,`begin`,`end`,`creator`,`modifier`,`creation`,`modification`,`code`,`order_date`,`deliver_date`,`title`,`description`,`contact`,`phone`,`fax`,`deliver_address`,`invoice_type`,`amount`,`discount_amount`,`status`,`org_id`,`partner_id`,`user_id`)
|
||||||
|
SELECT 1,'2025-05-20','9999-12-31','chengcai','chengcai',NOW(),NOW(),'SO00001','2025-05-10','2025-05-25','办公设备采购订单','含笔记本电脑及服务器,需上门安装调试。','张经理','13800138001',NULL,'上海市浦东新区张江高科技园区科苑路88号','10',24299.00,0.00,'9',1,17,11
|
||||||
|
FROM DUAL WHERE NOT EXISTS (SELECT 1 FROM sale_saleorder WHERE code='SO00001');
|
||||||
|
|
||||||
|
INSERT INTO `sale_saleorder`
|
||||||
|
(`id`,`begin`,`end`,`creator`,`modifier`,`creation`,`modification`,`code`,`order_date`,`deliver_date`,`title`,`description`,`contact`,`phone`,`fax`,`deliver_address`,`invoice_type`,`amount`,`discount_amount`,`status`,`org_id`,`partner_id`,`user_id`)
|
||||||
|
SELECT 2,'2025-05-20','9999-12-31','chengcai','chengcai',NOW(),NOW(),'SO00002','2025-05-15','2025-06-01','配电设备批量采购','项目现场配电改造用材。','李工','13900139002',NULL,'江苏省南京市江宁区将军大道29号','10',6400.00,200.00,'1',1,17,11
|
||||||
|
FROM DUAL WHERE NOT EXISTS (SELECT 1 FROM sale_saleorder WHERE code='SO00002');
|
||||||
|
|
||||||
|
INSERT INTO `sale_saleorder`
|
||||||
|
(`id`,`begin`,`end`,`creator`,`modifier`,`creation`,`modification`,`code`,`order_date`,`deliver_date`,`title`,`description`,`contact`,`phone`,`fax`,`deliver_address`,`invoice_type`,`amount`,`discount_amount`,`status`,`org_id`,`partner_id`,`user_id`)
|
||||||
|
SELECT 3,'2025-05-20','9999-12-31','chengcai','chengcai',NOW(),NOW(),'SO00003','2025-05-18','2025-05-22','水果批发季节订单','当季鲜果直采,分批配送。','王采购','13700137003',NULL,'浙江省杭州市余杭区良渚街道物流园A区','10',13962.00,0.00,'0',1,17,11
|
||||||
|
FROM DUAL WHERE NOT EXISTS (SELECT 1 FROM sale_saleorder WHERE code='SO00003');
|
||||||
|
|
||||||
|
INSERT INTO `sale_saleorder`
|
||||||
|
(`id`,`begin`,`end`,`creator`,`modifier`,`creation`,`modification`,`code`,`order_date`,`deliver_date`,`title`,`description`,`contact`,`phone`,`fax`,`deliver_address`,`invoice_type`,`amount`,`discount_amount`,`status`,`org_id`,`partner_id`,`user_id`)
|
||||||
|
SELECT 4,'2025-05-20','9999-12-31','chengcai','chengcai',NOW(),NOW(),'SO00004','2025-05-20','2025-05-28','劳保用品集中采购','车间一线员工劳保手套补充采购。','赵主任','13600136004',NULL,'安徽省合肥市蜀山区望江西路666号','10',5500.00,0.00,'9',1,17,11
|
||||||
|
FROM DUAL WHERE NOT EXISTS (SELECT 1 FROM sale_saleorder WHERE code='SO00004');
|
||||||
|
|
||||||
|
INSERT INTO `sale_saleitem` (`id`,`cnt`,`stock_price`,`sale_price`,`tax`,`create_time`,`status`,`event_time`,`master_id`,`material_id`,`measure_id`,`discount_price`)
|
||||||
|
SELECT 1,2.0000,NULL,7150.0000,'0.00',NOW(),0,NULL,1,53,1,NULL FROM DUAL WHERE NOT EXISTS (SELECT 1 FROM sale_saleitem WHERE id=1);
|
||||||
|
|
||||||
|
INSERT INTO `sale_saleitem` (`id`,`cnt`,`stock_price`,`sale_price`,`tax`,`create_time`,`status`,`event_time`,`master_id`,`material_id`,`measure_id`,`discount_price`)
|
||||||
|
SELECT 2,1.0000,NULL,9999.0000,'0.00',NOW(),0,NULL,1,54,1,NULL FROM DUAL WHERE NOT EXISTS (SELECT 1 FROM sale_saleitem WHERE id=2);
|
||||||
|
|
||||||
|
INSERT INTO `sale_saleitem` (`id`,`cnt`,`stock_price`,`sale_price`,`tax`,`create_time`,`status`,`event_time`,`master_id`,`material_id`,`measure_id`,`discount_price`)
|
||||||
|
SELECT 3,20.0000,NULL,320.0000,'0.00',NOW(),0,NULL,2,52,1,NULL FROM DUAL WHERE NOT EXISTS (SELECT 1 FROM sale_saleitem WHERE id=3);
|
||||||
|
|
||||||
|
INSERT INTO `sale_saleitem` (`id`,`cnt`,`stock_price`,`sale_price`,`tax`,`create_time`,`status`,`event_time`,`master_id`,`material_id`,`measure_id`,`discount_price`)
|
||||||
|
SELECT 4,500.0000,NULL,10.9200,'0.00',NOW(),0,NULL,3,40,3,NULL FROM DUAL WHERE NOT EXISTS (SELECT 1 FROM sale_saleitem WHERE id=4);
|
||||||
|
|
||||||
|
INSERT INTO `sale_saleitem` (`id`,`cnt`,`stock_price`,`sale_price`,`tax`,`create_time`,`status`,`event_time`,`master_id`,`material_id`,`measure_id`,`discount_price`)
|
||||||
|
SELECT 5,300.0000,NULL,15.9900,'0.00',NOW(),0,NULL,3,41,3,NULL FROM DUAL WHERE NOT EXISTS (SELECT 1 FROM sale_saleitem WHERE id=5);
|
||||||
|
|
||||||
|
INSERT INTO `sale_saleitem` (`id`,`cnt`,`stock_price`,`sale_price`,`tax`,`create_time`,`status`,`event_time`,`master_id`,`material_id`,`measure_id`,`discount_price`)
|
||||||
|
SELECT 6,200.0000,NULL,18.5250,'0.00',NOW(),0,NULL,3,42,3,NULL FROM DUAL WHERE NOT EXISTS (SELECT 1 FROM sale_saleitem WHERE id=6);
|
||||||
|
|
||||||
|
INSERT INTO `sale_saleitem` (`id`,`cnt`,`stock_price`,`sale_price`,`tax`,`create_time`,`status`,`event_time`,`master_id`,`material_id`,`measure_id`,`discount_price`)
|
||||||
|
SELECT 7,1000.0000,NULL,5.5000,'0.00',NOW(),0,NULL,4,5,1,NULL FROM DUAL WHERE NOT EXISTS (SELECT 1 FROM sale_saleitem WHERE id=7);
|
||||||
@@ -0,0 +1,170 @@
|
|||||||
|
# -*- coding: utf-8 -*-
|
||||||
|
"""导入销售订单示例数据。用法: python Install/load_sale_sample.py"""
|
||||||
|
import os
|
||||||
|
import sys
|
||||||
|
import datetime
|
||||||
|
|
||||||
|
BASE_DIR = os.path.dirname(os.path.dirname(os.path.abspath(__file__)))
|
||||||
|
if BASE_DIR not in sys.path:
|
||||||
|
sys.path.insert(0, BASE_DIR)
|
||||||
|
|
||||||
|
os.environ.setdefault('DJANGO_SETTINGS_MODULE', 'mis.settings')
|
||||||
|
|
||||||
|
import django
|
||||||
|
django.setup()
|
||||||
|
|
||||||
|
from decimal import Decimal
|
||||||
|
from django.contrib.auth.models import User
|
||||||
|
from django.db import transaction
|
||||||
|
from basedata.models import Partner, Material, Organization
|
||||||
|
from sale.models import SaleOrder, SaleItem
|
||||||
|
|
||||||
|
|
||||||
|
def recalc_order_amount(order):
|
||||||
|
total = Decimal('0')
|
||||||
|
for item in SaleItem.objects.filter(master=order):
|
||||||
|
price = item.sale_price or Decimal('0')
|
||||||
|
total += price * item.cnt
|
||||||
|
SaleOrder.objects.filter(pk=order.pk).update(amount=total)
|
||||||
|
order.amount = total
|
||||||
|
return total
|
||||||
|
|
||||||
|
|
||||||
|
SAMPLE_ORDERS = [
|
||||||
|
{
|
||||||
|
'code': 'SO00001',
|
||||||
|
'title': u'办公设备采购订单',
|
||||||
|
'order_date': datetime.date(2025, 5, 10),
|
||||||
|
'deliver_date': datetime.date(2025, 5, 25),
|
||||||
|
'contact': u'张经理',
|
||||||
|
'phone': '13800138001',
|
||||||
|
'deliver_address': u'上海市浦东新区张江高科技园区科苑路88号',
|
||||||
|
'description': u'含笔记本电脑及服务器,需上门安装调试。',
|
||||||
|
'status': '9',
|
||||||
|
'discount_amount': 0,
|
||||||
|
'items': [
|
||||||
|
{'material_code': 'IT5001', 'cnt': 2, 'sale_price': 7150.00},
|
||||||
|
{'material_code': 'IT5002', 'cnt': 1, 'sale_price': 9999.00},
|
||||||
|
],
|
||||||
|
},
|
||||||
|
{
|
||||||
|
'code': 'SO00002',
|
||||||
|
'title': u'配电设备批量采购',
|
||||||
|
'order_date': datetime.date(2025, 5, 15),
|
||||||
|
'deliver_date': datetime.date(2025, 6, 1),
|
||||||
|
'contact': u'李工',
|
||||||
|
'phone': '13900139002',
|
||||||
|
'deliver_address': u'江苏省南京市江宁区将军大道29号',
|
||||||
|
'description': u'项目现场配电改造用材。',
|
||||||
|
'status': '1',
|
||||||
|
'discount_amount': 200.00,
|
||||||
|
'items': [
|
||||||
|
{'material_code': 'IT9981', 'cnt': 20, 'sale_price': 320.00},
|
||||||
|
],
|
||||||
|
},
|
||||||
|
{
|
||||||
|
'code': 'SO00003',
|
||||||
|
'title': u'水果批发季节订单',
|
||||||
|
'order_date': datetime.date(2025, 5, 18),
|
||||||
|
'deliver_date': datetime.date(2025, 5, 22),
|
||||||
|
'contact': u'王采购',
|
||||||
|
'phone': '13700137003',
|
||||||
|
'deliver_address': u'浙江省杭州市余杭区良渚街道物流园A区',
|
||||||
|
'description': u'当季鲜果直采,分批配送。',
|
||||||
|
'status': '0',
|
||||||
|
'discount_amount': 0,
|
||||||
|
'items': [
|
||||||
|
{'material_code': 'IT9001', 'cnt': 500, 'sale_price': 11.00},
|
||||||
|
{'material_code': 'IT9002', 'cnt': 300, 'sale_price': 16.00},
|
||||||
|
{'material_code': 'IT9003', 'cnt': 200, 'sale_price': 19.00},
|
||||||
|
],
|
||||||
|
},
|
||||||
|
{
|
||||||
|
'code': 'SO00004',
|
||||||
|
'title': u'劳保用品集中采购',
|
||||||
|
'order_date': datetime.date(2025, 5, 20),
|
||||||
|
'deliver_date': datetime.date(2025, 5, 28),
|
||||||
|
'contact': u'赵主任',
|
||||||
|
'phone': '13600136004',
|
||||||
|
'deliver_address': u'安徽省合肥市蜀山区望江西路666号',
|
||||||
|
'description': u'车间一线员工劳保手套补充采购。',
|
||||||
|
'status': '9',
|
||||||
|
'discount_amount': 0,
|
||||||
|
'items': [
|
||||||
|
{'material_code': 'IT00005', 'cnt': 1000, 'sale_price': 5.50},
|
||||||
|
],
|
||||||
|
},
|
||||||
|
]
|
||||||
|
|
||||||
|
|
||||||
|
def load_samples():
|
||||||
|
partner = Partner.objects.filter(partner_type='C').first()
|
||||||
|
if not partner:
|
||||||
|
print(u'错误: 未找到客户类型合作伙伴,请先维护基础数据。')
|
||||||
|
return
|
||||||
|
|
||||||
|
user = User.objects.filter(username='chengcai').first() or User.objects.first()
|
||||||
|
org = Organization.objects.first()
|
||||||
|
creator = user.username if user else 'system'
|
||||||
|
today = datetime.date.today()
|
||||||
|
|
||||||
|
created = 0
|
||||||
|
skipped = 0
|
||||||
|
|
||||||
|
with transaction.atomic():
|
||||||
|
for data in SAMPLE_ORDERS:
|
||||||
|
if SaleOrder.objects.filter(code=data['code']).exists():
|
||||||
|
print(u'跳过已存在订单: %s' % data['code'])
|
||||||
|
skipped += 1
|
||||||
|
continue
|
||||||
|
|
||||||
|
order = SaleOrder(
|
||||||
|
code=data['code'],
|
||||||
|
title=data['title'],
|
||||||
|
order_date=data['order_date'],
|
||||||
|
deliver_date=data['deliver_date'],
|
||||||
|
partner=partner,
|
||||||
|
org=org,
|
||||||
|
user=user,
|
||||||
|
contact=data['contact'],
|
||||||
|
phone=data['phone'],
|
||||||
|
deliver_address=data['deliver_address'],
|
||||||
|
description=data['description'],
|
||||||
|
invoice_type='10',
|
||||||
|
status=data['status'],
|
||||||
|
discount_amount=data['discount_amount'],
|
||||||
|
amount=0,
|
||||||
|
begin=today,
|
||||||
|
end=datetime.date(9999, 12, 31),
|
||||||
|
creator=creator,
|
||||||
|
modifier=creator,
|
||||||
|
)
|
||||||
|
order.save()
|
||||||
|
|
||||||
|
for item_data in data['items']:
|
||||||
|
material = Material.objects.filter(code=item_data['material_code']).first()
|
||||||
|
if not material:
|
||||||
|
print(u'警告: 物料 %s 不存在,已跳过' % item_data['material_code'])
|
||||||
|
continue
|
||||||
|
item = SaleItem(
|
||||||
|
master=order,
|
||||||
|
material=material,
|
||||||
|
cnt=item_data['cnt'],
|
||||||
|
sale_price=item_data['sale_price'],
|
||||||
|
tax='0.00',
|
||||||
|
)
|
||||||
|
item.save()
|
||||||
|
|
||||||
|
if data['discount_amount'] > 0:
|
||||||
|
order.save()
|
||||||
|
total = recalc_order_amount(order)
|
||||||
|
print(u'已创建: %s %s 金额=%s 状态=%s' % (
|
||||||
|
order.code, order.title, total, order.get_status_display()
|
||||||
|
))
|
||||||
|
created += 1
|
||||||
|
|
||||||
|
print(u'\n完成: 新增 %d 条,跳过 %d 条。' % (created, skipped))
|
||||||
|
|
||||||
|
|
||||||
|
if __name__ == '__main__':
|
||||||
|
load_samples()
|
||||||
@@ -3,15 +3,15 @@
|
|||||||
# This file is distributed under the same license as the PACKAGE package.
|
# This file is distributed under the same license as the PACKAGE package.
|
||||||
# FIRST AUTHOR <EMAIL@ADDRESS>, YEAR.
|
# FIRST AUTHOR <EMAIL@ADDRESS>, YEAR.
|
||||||
#
|
#
|
||||||
#, fuzzy
|
|
||||||
msgid ""
|
msgid ""
|
||||||
msgstr ""
|
msgstr ""
|
||||||
"Project-Id-Version: PACKAGE VERSION\n"
|
"Project-Id-Version: PACKAGE VERSION\n"
|
||||||
"Report-Msgid-Bugs-To: \n"
|
"Report-Msgid-Bugs-To: \n"
|
||||||
"POT-Creation-Date: 2015-05-01 19:18+0800\n"
|
"POT-Creation-Date: 2015-05-01 19:18+0800\n"
|
||||||
"PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n"
|
"PO-Revision-Date: 2026-06-10 12:00+0800\n"
|
||||||
"Last-Translator: FULL NAME <EMAIL@ADDRESS>\n"
|
"Last-Translator: \n"
|
||||||
"Language-Team: LANGUAGE <LL@li.org>\n"
|
"Language-Team: zh_Hans\n"
|
||||||
|
"Language: zh_Hans\n"
|
||||||
"MIME-Version: 1.0\n"
|
"MIME-Version: 1.0\n"
|
||||||
"Content-Type: text/plain; charset=UTF-8\n"
|
"Content-Type: text/plain; charset=UTF-8\n"
|
||||||
"Content-Transfer-Encoding: 8bit\n"
|
"Content-Transfer-Encoding: 8bit\n"
|
||||||
@@ -750,6 +750,9 @@ msgstr "提交"
|
|||||||
msgid "AGREE"
|
msgid "AGREE"
|
||||||
msgstr "同意"
|
msgstr "同意"
|
||||||
|
|
||||||
|
msgid "object id"
|
||||||
|
msgstr "对象 ID"
|
||||||
|
|
||||||
msgid "workflow instance"
|
msgid "workflow instance"
|
||||||
msgstr "工作流实例"
|
msgstr "工作流实例"
|
||||||
|
|
||||||
|
|||||||
File diff suppressed because it is too large
Load Diff
+3
-1
@@ -49,6 +49,7 @@ INSTALLED_APPS = (
|
|||||||
|
|
||||||
MIDDLEWARE_CLASSES = (
|
MIDDLEWARE_CLASSES = (
|
||||||
'django.contrib.sessions.middleware.SessionMiddleware',
|
'django.contrib.sessions.middleware.SessionMiddleware',
|
||||||
|
'django.middleware.locale.LocaleMiddleware',
|
||||||
'django.middleware.common.CommonMiddleware',
|
'django.middleware.common.CommonMiddleware',
|
||||||
'django.middleware.csrf.CsrfViewMiddleware',
|
'django.middleware.csrf.CsrfViewMiddleware',
|
||||||
'django.contrib.auth.middleware.AuthenticationMiddleware',
|
'django.contrib.auth.middleware.AuthenticationMiddleware',
|
||||||
@@ -89,6 +90,7 @@ DATABASES = {
|
|||||||
'default': {
|
'default': {
|
||||||
'ENGINE': 'django.db.backends.mysql',
|
'ENGINE': 'django.db.backends.mysql',
|
||||||
'HOST': os.environ.get('DATABASE_HOST', 'localhost'),
|
'HOST': os.environ.get('DATABASE_HOST', 'localhost'),
|
||||||
|
'PORT': os.environ.get('DATABASE_PORT', '3306'),
|
||||||
'NAME': os.environ.get('DATABASE_NAME', 'mis'),
|
'NAME': os.environ.get('DATABASE_NAME', 'mis'),
|
||||||
'USER': os.environ.get('DATABASE_USER', 'root'),
|
'USER': os.environ.get('DATABASE_USER', 'root'),
|
||||||
'PASSWORD': os.environ.get('DATABASE_PASSWORD', 'root'),
|
'PASSWORD': os.environ.get('DATABASE_PASSWORD', 'root'),
|
||||||
@@ -99,7 +101,7 @@ DATABASES = {
|
|||||||
# Internationalization
|
# Internationalization
|
||||||
# https://docs.djangoproject.com/en/1.8/topics/i18n/
|
# https://docs.djangoproject.com/en/1.8/topics/i18n/
|
||||||
|
|
||||||
LANGUAGE_CODE = 'zh-CN'
|
LANGUAGE_CODE = 'zh-hans'
|
||||||
|
|
||||||
LOCALE_PATHS = [os.path.join(BASE_DIR, 'locale')]
|
LOCALE_PATHS = [os.path.join(BASE_DIR, 'locale')]
|
||||||
|
|
||||||
|
|||||||
@@ -0,0 +1,984 @@
|
|||||||
|
/* 智捷ERP SmartJet ERP - 1:1 High-Fidelity UI System v4.0 */
|
||||||
|
@import url('https://fonts.googleapis.com/css2?family=Plus+Jakarta+Sans:wght@400;500;600;700;800&display=swap');
|
||||||
|
|
||||||
|
:root {
|
||||||
|
--primary: #6366f1;
|
||||||
|
--primary-light: #818cf8;
|
||||||
|
--primary-bg: #f5f3ff;
|
||||||
|
|
||||||
|
--slate-50: #f8fafc;
|
||||||
|
--slate-100: #f1f5f9;
|
||||||
|
--slate-200: #e2e8f0;
|
||||||
|
--slate-300: #cbd5e1;
|
||||||
|
--slate-400: #94a3b8;
|
||||||
|
--slate-500: #64748b;
|
||||||
|
--slate-600: #475569;
|
||||||
|
--slate-700: #334155;
|
||||||
|
--slate-800: #1e293b;
|
||||||
|
--slate-900: #0f172a;
|
||||||
|
|
||||||
|
--success: #10b981;
|
||||||
|
--warning: #f59e0b;
|
||||||
|
--danger: #ef4444;
|
||||||
|
--info: #3b82f6;
|
||||||
|
|
||||||
|
--sidebar-width: 240px;
|
||||||
|
--sidebar-collapsed-width: 0px;
|
||||||
|
--topbar-height: 64px;
|
||||||
|
--radius-lg: 16px;
|
||||||
|
--radius-md: 10px;
|
||||||
|
--shadow-card: 0 10px 15px -3px rgba(0, 0, 0, 0.04), 0 4px 6px -2px rgba(0, 0, 0, 0.02);
|
||||||
|
}
|
||||||
|
|
||||||
|
*, *::before, *::after {
|
||||||
|
box-sizing: border-box;
|
||||||
|
}
|
||||||
|
|
||||||
|
body {
|
||||||
|
background-color: #f1f5f9 !important;
|
||||||
|
color: var(--slate-800) !important;
|
||||||
|
font-family: 'Plus Jakarta Sans', -apple-system, sans-serif !important;
|
||||||
|
margin: 0 !important;
|
||||||
|
padding: 0 !important;
|
||||||
|
overflow-x: hidden;
|
||||||
|
}
|
||||||
|
|
||||||
|
#container {
|
||||||
|
display: flex !important;
|
||||||
|
min-height: 100vh;
|
||||||
|
min-width: 0 !important;
|
||||||
|
max-width: 100vw;
|
||||||
|
width: 100%;
|
||||||
|
overflow-x: hidden;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* --- SIDEBAR --- */
|
||||||
|
#header {
|
||||||
|
width: var(--sidebar-width) !important;
|
||||||
|
height: 100vh !important;
|
||||||
|
position: fixed !important;
|
||||||
|
left: 0; top: 0;
|
||||||
|
background: #ffffff !important;
|
||||||
|
border-right: 1px solid var(--slate-200) !important;
|
||||||
|
padding: 0 !important;
|
||||||
|
display: flex !important;
|
||||||
|
flex-direction: column !important;
|
||||||
|
z-index: 1000 !important;
|
||||||
|
color: var(--slate-800) !important;
|
||||||
|
line-height: normal !important;
|
||||||
|
overflow: visible !important;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* 覆盖 Django admin 默认深色顶栏链接样式(白字导致侧栏文字不可见) */
|
||||||
|
#header a:link,
|
||||||
|
#header a:visited {
|
||||||
|
color: inherit !important;
|
||||||
|
text-decoration: none !important;
|
||||||
|
}
|
||||||
|
|
||||||
|
#header a:focus,
|
||||||
|
#header a:hover {
|
||||||
|
text-decoration: none !important;
|
||||||
|
}
|
||||||
|
|
||||||
|
.brand-section {
|
||||||
|
padding: 24px;
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
}
|
||||||
|
|
||||||
|
.brand-logo {
|
||||||
|
width: 32px;
|
||||||
|
height: 32px;
|
||||||
|
background: linear-gradient(135deg, #6366f1, #a855f7);
|
||||||
|
border-radius: 8px;
|
||||||
|
margin-right: 12px;
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
justify-content: center;
|
||||||
|
color: white;
|
||||||
|
font-weight: 800;
|
||||||
|
}
|
||||||
|
|
||||||
|
.brand-text h1 {
|
||||||
|
font-size: 18px !important;
|
||||||
|
font-weight: 800 !important;
|
||||||
|
color: #1e293b !important;
|
||||||
|
margin: 0 !important;
|
||||||
|
line-height: 1 !important;
|
||||||
|
}
|
||||||
|
|
||||||
|
.brand-text span {
|
||||||
|
font-size: 11px;
|
||||||
|
color: var(--slate-400);
|
||||||
|
text-transform: uppercase;
|
||||||
|
letter-spacing: 0.05em;
|
||||||
|
}
|
||||||
|
|
||||||
|
.sidebar-nav {
|
||||||
|
flex: 1;
|
||||||
|
padding: 0 16px;
|
||||||
|
overflow-y: auto;
|
||||||
|
}
|
||||||
|
|
||||||
|
.nav-group-label {
|
||||||
|
padding: 20px 12px 10px 12px;
|
||||||
|
color: var(--slate-400);
|
||||||
|
font-size: 11px;
|
||||||
|
font-weight: 700;
|
||||||
|
text-transform: uppercase;
|
||||||
|
}
|
||||||
|
|
||||||
|
.nav-item {
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
padding: 12px 16px;
|
||||||
|
border-radius: 12px;
|
||||||
|
color: var(--slate-600) !important;
|
||||||
|
text-decoration: none !important;
|
||||||
|
font-weight: 600;
|
||||||
|
font-size: 14px;
|
||||||
|
margin-bottom: 4px;
|
||||||
|
transition: all 0.2s;
|
||||||
|
}
|
||||||
|
|
||||||
|
.nav-item:hover,
|
||||||
|
.nav-item:focus {
|
||||||
|
background: var(--slate-50);
|
||||||
|
color: var(--primary) !important;
|
||||||
|
}
|
||||||
|
|
||||||
|
.nav-item.active,
|
||||||
|
.nav-item.active:link,
|
||||||
|
.nav-item.active:visited {
|
||||||
|
background: var(--primary-bg) !important;
|
||||||
|
color: var(--primary) !important;
|
||||||
|
}
|
||||||
|
|
||||||
|
.nav-item i { margin-right: 12px; font-size: 18px; width: 20px; text-align: center; }
|
||||||
|
.nav-item .arrow { margin-left: auto; font-size: 10px; color: var(--slate-300); }
|
||||||
|
|
||||||
|
.sidebar-footer {
|
||||||
|
padding: 16px;
|
||||||
|
border-top: 1px solid var(--slate-100);
|
||||||
|
position: relative;
|
||||||
|
z-index: 1002;
|
||||||
|
flex-shrink: 0;
|
||||||
|
background: #ffffff;
|
||||||
|
}
|
||||||
|
|
||||||
|
.nav-item-btn {
|
||||||
|
width: 100%;
|
||||||
|
border: none;
|
||||||
|
background: transparent;
|
||||||
|
cursor: pointer;
|
||||||
|
font-family: inherit;
|
||||||
|
text-align: left;
|
||||||
|
}
|
||||||
|
|
||||||
|
button.nav-item-btn:hover,
|
||||||
|
button.nav-item-btn:focus {
|
||||||
|
background: var(--slate-50);
|
||||||
|
color: var(--primary) !important;
|
||||||
|
outline: none;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* 侧栏收起 */
|
||||||
|
#header {
|
||||||
|
transition: transform 0.25s ease;
|
||||||
|
}
|
||||||
|
|
||||||
|
body.sidebar-collapsed #header {
|
||||||
|
transform: translateX(-100%);
|
||||||
|
pointer-events: none;
|
||||||
|
}
|
||||||
|
|
||||||
|
body.sidebar-collapsed #main {
|
||||||
|
margin-left: 0 !important;
|
||||||
|
max-width: 100vw !important;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* --- TOPBAR --- */
|
||||||
|
#main {
|
||||||
|
flex: 1 1 auto !important;
|
||||||
|
margin-left: var(--sidebar-width) !important;
|
||||||
|
width: auto !important;
|
||||||
|
min-width: 0 !important;
|
||||||
|
max-width: calc(100vw - var(--sidebar-width)) !important;
|
||||||
|
overflow-x: hidden;
|
||||||
|
position: relative;
|
||||||
|
z-index: 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
.topbar {
|
||||||
|
height: var(--topbar-height);
|
||||||
|
background: #ffffff !important;
|
||||||
|
opacity: 1 !important;
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
padding: 0 32px;
|
||||||
|
position: sticky;
|
||||||
|
top: 0;
|
||||||
|
z-index: 900;
|
||||||
|
box-shadow: 0 1px 2px rgba(0,0,0,0.02);
|
||||||
|
}
|
||||||
|
|
||||||
|
.topbar-left { display: flex; align-items: center; flex: 1; }
|
||||||
|
.topbar-right {
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
gap: 20px;
|
||||||
|
background: #ffffff !important;
|
||||||
|
opacity: 1 !important;
|
||||||
|
position: relative;
|
||||||
|
z-index: 901;
|
||||||
|
pointer-events: auto;
|
||||||
|
}
|
||||||
|
|
||||||
|
.breadcrumb-new {
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
gap: 8px;
|
||||||
|
font-size: 13px;
|
||||||
|
color: var(--slate-400);
|
||||||
|
margin-left: 20px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.breadcrumb-new span { color: var(--slate-800); font-weight: 600; }
|
||||||
|
|
||||||
|
.search-btn, .icon-btn {
|
||||||
|
width: 36px;
|
||||||
|
height: 36px;
|
||||||
|
border-radius: 50%;
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
justify-content: center;
|
||||||
|
color: var(--slate-500);
|
||||||
|
cursor: pointer;
|
||||||
|
transition: background 0.2s;
|
||||||
|
border: none;
|
||||||
|
background: transparent;
|
||||||
|
padding: 0;
|
||||||
|
font-size: 16px;
|
||||||
|
line-height: 1;
|
||||||
|
pointer-events: auto;
|
||||||
|
position: relative;
|
||||||
|
z-index: 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
.search-btn:hover, .icon-btn:hover,
|
||||||
|
.search-btn:focus, .icon-btn:focus {
|
||||||
|
background: var(--slate-100);
|
||||||
|
outline: none;
|
||||||
|
}
|
||||||
|
|
||||||
|
.user-menu-wrap {
|
||||||
|
position: relative;
|
||||||
|
padding-left: 20px;
|
||||||
|
border-left: 1px solid var(--slate-200);
|
||||||
|
}
|
||||||
|
|
||||||
|
.user-profile {
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
gap: 12px;
|
||||||
|
padding: 4px 8px;
|
||||||
|
border: none;
|
||||||
|
border-radius: 10px;
|
||||||
|
background: #ffffff !important;
|
||||||
|
opacity: 1 !important;
|
||||||
|
cursor: pointer;
|
||||||
|
font-family: inherit;
|
||||||
|
pointer-events: auto;
|
||||||
|
}
|
||||||
|
|
||||||
|
.user-profile:hover,
|
||||||
|
.user-profile:focus {
|
||||||
|
background: var(--slate-50) !important;
|
||||||
|
outline: none;
|
||||||
|
}
|
||||||
|
|
||||||
|
.user-caret {
|
||||||
|
font-size: 10px;
|
||||||
|
color: var(--slate-400);
|
||||||
|
margin-left: 4px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.user-dropdown {
|
||||||
|
display: none;
|
||||||
|
position: absolute;
|
||||||
|
top: calc(100% + 8px);
|
||||||
|
right: 0;
|
||||||
|
min-width: 140px;
|
||||||
|
background: #ffffff;
|
||||||
|
border: 1px solid var(--slate-200);
|
||||||
|
border-radius: 10px;
|
||||||
|
box-shadow: 0 10px 25px rgba(0, 0, 0, 0.1);
|
||||||
|
padding: 6px;
|
||||||
|
z-index: 1100;
|
||||||
|
}
|
||||||
|
|
||||||
|
.user-dropdown.open {
|
||||||
|
display: block;
|
||||||
|
}
|
||||||
|
|
||||||
|
.user-dropdown a {
|
||||||
|
display: block;
|
||||||
|
padding: 10px 14px;
|
||||||
|
border-radius: 8px;
|
||||||
|
color: var(--slate-700) !important;
|
||||||
|
text-decoration: none !important;
|
||||||
|
font-size: 13px;
|
||||||
|
font-weight: 600;
|
||||||
|
}
|
||||||
|
|
||||||
|
.user-dropdown a:hover {
|
||||||
|
background: var(--slate-50);
|
||||||
|
color: var(--primary) !important;
|
||||||
|
}
|
||||||
|
|
||||||
|
.avatar {
|
||||||
|
width: 36px;
|
||||||
|
height: 36px;
|
||||||
|
border-radius: 10px;
|
||||||
|
background: var(--slate-200);
|
||||||
|
flex-shrink: 0;
|
||||||
|
opacity: 1 !important;
|
||||||
|
}
|
||||||
|
|
||||||
|
.user-info { display: flex; flex-direction: column; background: transparent; }
|
||||||
|
.user-name { font-weight: 700; font-size: 13px; color: var(--slate-800) !important; opacity: 1 !important; }
|
||||||
|
.user-role { font-size: 11px; color: var(--slate-500) !important; opacity: 1 !important; }
|
||||||
|
|
||||||
|
/* --- CONTENT --- */
|
||||||
|
#content {
|
||||||
|
padding: 32px !important;
|
||||||
|
width: 100% !important;
|
||||||
|
max-width: 100% !important;
|
||||||
|
min-width: 0 !important;
|
||||||
|
position: relative;
|
||||||
|
z-index: 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
.dashboard #content {
|
||||||
|
width: 100% !important;
|
||||||
|
max-width: 100% !important;
|
||||||
|
}
|
||||||
|
|
||||||
|
#content-main {
|
||||||
|
float: none !important;
|
||||||
|
width: 100% !important;
|
||||||
|
max-width: 100% !important;
|
||||||
|
min-width: 0 !important;
|
||||||
|
}
|
||||||
|
|
||||||
|
.dashboard #content > h1 {
|
||||||
|
display: none;
|
||||||
|
}
|
||||||
|
|
||||||
|
#content > h1 {
|
||||||
|
font-size: 22px;
|
||||||
|
font-weight: 700;
|
||||||
|
color: var(--slate-900);
|
||||||
|
margin: 0 0 24px;
|
||||||
|
padding-right: 120px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.colM, .colMS {
|
||||||
|
max-width: 100%;
|
||||||
|
min-width: 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
#changelist, #changelist-form, .results {
|
||||||
|
max-width: 100%;
|
||||||
|
overflow-x: auto;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* --- STATS CARDS --- */
|
||||||
|
.stats-grid {
|
||||||
|
display: grid;
|
||||||
|
grid-template-columns: repeat(4, minmax(0, 1fr));
|
||||||
|
gap: 24px;
|
||||||
|
margin-bottom: 32px;
|
||||||
|
width: 100%;
|
||||||
|
max-width: 100%;
|
||||||
|
}
|
||||||
|
|
||||||
|
.stat-card {
|
||||||
|
background: #ffffff;
|
||||||
|
padding: 24px;
|
||||||
|
border-radius: var(--radius-lg);
|
||||||
|
box-shadow: var(--shadow-card);
|
||||||
|
position: relative;
|
||||||
|
min-width: 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
.stat-header { display: flex; justify-content: space-between; margin-bottom: 12px; }
|
||||||
|
.stat-icon-bg { width: 40px; height: 40px; border-radius: 12px; display: flex; align-items: center; justify-content: center; color: white; font-size: 18px; }
|
||||||
|
.stat-info-icon { color: var(--slate-300); font-size: 14px; cursor: help; }
|
||||||
|
|
||||||
|
.stat-value { font-size: 24px; font-weight: 800; color: var(--slate-900); margin-bottom: 8px; }
|
||||||
|
.stat-label { font-size: 14px; color: var(--slate-500); font-weight: 500; }
|
||||||
|
|
||||||
|
.stat-footer { display: flex; align-items: center; justify-content: space-between; margin-top: 16px; border-top: 1px solid var(--slate-50); padding-top: 16px; }
|
||||||
|
.stat-trend { font-size: 12px; font-weight: 600; display: flex; align-items: center; gap: 4px; }
|
||||||
|
.trend-up { color: var(--success); }
|
||||||
|
.trend-down { color: var(--danger); }
|
||||||
|
|
||||||
|
.sparkline { width: 60px; height: 30px; }
|
||||||
|
|
||||||
|
/* --- DATA MODULES --- */
|
||||||
|
.dashboard-main-grid {
|
||||||
|
display: grid;
|
||||||
|
grid-template-columns: minmax(0, 1fr) minmax(260px, 340px);
|
||||||
|
gap: 24px;
|
||||||
|
width: 100%;
|
||||||
|
max-width: 100%;
|
||||||
|
}
|
||||||
|
|
||||||
|
.module-card {
|
||||||
|
background: white;
|
||||||
|
border-radius: var(--radius-lg);
|
||||||
|
box-shadow: var(--shadow-card);
|
||||||
|
overflow: hidden;
|
||||||
|
display: flex;
|
||||||
|
flex-direction: column;
|
||||||
|
min-width: 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
.card-title {
|
||||||
|
padding: 24px 32px;
|
||||||
|
font-size: 16px;
|
||||||
|
font-weight: 700;
|
||||||
|
color: var(--slate-900);
|
||||||
|
display: flex;
|
||||||
|
justify-content: space-between;
|
||||||
|
align-items: center;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* --- TABLE STYLES --- */
|
||||||
|
.table-container { overflow-x: auto; max-width: 100%; padding: 0 12px 12px 12px; }
|
||||||
|
table { width: 100%; max-width: 100%; border-collapse: collapse; }
|
||||||
|
th { text-align: left; padding: 12px 20px; font-size: 12px; color: var(--slate-400); font-weight: 600; border-bottom: 1px solid var(--slate-100); }
|
||||||
|
td { padding: 16px 20px; font-size: 13px; color: var(--slate-700); border-bottom: 1px solid var(--slate-50); }
|
||||||
|
tr:last-child td { border: none; }
|
||||||
|
|
||||||
|
.badge {
|
||||||
|
padding: 4px 10px;
|
||||||
|
border-radius: 6px;
|
||||||
|
font-size: 11px;
|
||||||
|
font-weight: 700;
|
||||||
|
}
|
||||||
|
.badge-new { background: #eef2ff; color: #6366f1; }
|
||||||
|
.badge-audit { background: #ecfdf5; color: #10b981; }
|
||||||
|
.badge-update { background: #eff6ff; color: #3b82f6; }
|
||||||
|
.badge-submit { background: #fff7ed; color: #f97316; }
|
||||||
|
|
||||||
|
/* --- TASK LIST --- */
|
||||||
|
.task-list { padding: 0 24px 24px 24px; }
|
||||||
|
.task-item {
|
||||||
|
display: flex;
|
||||||
|
align-items: flex-start;
|
||||||
|
gap: 16px;
|
||||||
|
padding: 16px;
|
||||||
|
border-radius: 12px;
|
||||||
|
margin-bottom: 12px;
|
||||||
|
background: #ffffff;
|
||||||
|
border: 1px solid var(--slate-50);
|
||||||
|
transition: all 0.2s;
|
||||||
|
}
|
||||||
|
.task-item:hover { border-color: var(--slate-200); background: var(--slate-50); }
|
||||||
|
|
||||||
|
.task-icon { width: 36px; height: 36px; border-radius: 10px; display: flex; align-items: center; justify-content: center; font-size: 16px; color: white; }
|
||||||
|
.task-content { flex: 1; }
|
||||||
|
.task-name { font-size: 13px; font-weight: 700; color: var(--slate-800); }
|
||||||
|
.task-info { font-size: 11px; color: var(--slate-400); margin-top: 2px; }
|
||||||
|
.task-time { font-size: 11px; color: var(--slate-400); }
|
||||||
|
|
||||||
|
.priority-tag { font-size: 10px; font-weight: 800; padding: 2px 6px; border-radius: 4px; text-transform: uppercase; margin-top: 8px; display: inline-block; }
|
||||||
|
.p-urgent { background: #fef2f2; color: #ef4444; }
|
||||||
|
.p-high { background: #fff7ed; color: #f97316; }
|
||||||
|
.p-medium { background: #fffbeb; color: #f59e0b; }
|
||||||
|
.p-low { background: #f0fdf4; color: #10b981; }
|
||||||
|
|
||||||
|
.view-all { text-align: center; padding: 20px; border-top: 1px solid var(--slate-50); }
|
||||||
|
.view-all a { color: var(--primary); text-decoration: none; font-size: 13px; font-weight: 700; }
|
||||||
|
|
||||||
|
/* --- ADMIN FORM ACTIONS --- */
|
||||||
|
#content-main {
|
||||||
|
position: relative;
|
||||||
|
padding-bottom: 24px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.object-tools {
|
||||||
|
float: none !important;
|
||||||
|
position: absolute !important;
|
||||||
|
top: 32px;
|
||||||
|
right: 32px;
|
||||||
|
margin: 0 !important;
|
||||||
|
padding: 0 !important;
|
||||||
|
font-size: 12px !important;
|
||||||
|
font-weight: 600 !important;
|
||||||
|
opacity: 1 !important;
|
||||||
|
z-index: 5;
|
||||||
|
pointer-events: auto;
|
||||||
|
}
|
||||||
|
|
||||||
|
.object-tools li {
|
||||||
|
height: auto !important;
|
||||||
|
margin-left: 0 !important;
|
||||||
|
}
|
||||||
|
|
||||||
|
.object-tools a:link,
|
||||||
|
.object-tools a:visited,
|
||||||
|
.object-tools a.historylink {
|
||||||
|
display: inline-flex !important;
|
||||||
|
align-items: center;
|
||||||
|
float: none !important;
|
||||||
|
padding: 8px 16px !important;
|
||||||
|
background: var(--slate-600) !important;
|
||||||
|
color: #ffffff !important;
|
||||||
|
opacity: 1 !important;
|
||||||
|
border-radius: 8px !important;
|
||||||
|
font-size: 12px !important;
|
||||||
|
font-weight: 600 !important;
|
||||||
|
text-transform: none !important;
|
||||||
|
letter-spacing: 0 !important;
|
||||||
|
text-decoration: none !important;
|
||||||
|
}
|
||||||
|
|
||||||
|
.object-tools a:hover,
|
||||||
|
.object-tools a:focus {
|
||||||
|
background: var(--slate-700) !important;
|
||||||
|
color: #ffffff !important;
|
||||||
|
opacity: 1 !important;
|
||||||
|
}
|
||||||
|
|
||||||
|
.submit-row {
|
||||||
|
display: flex !important;
|
||||||
|
flex-wrap: wrap;
|
||||||
|
align-items: center;
|
||||||
|
justify-content: flex-end;
|
||||||
|
gap: 10px;
|
||||||
|
overflow: visible !important;
|
||||||
|
padding: 16px 20px !important;
|
||||||
|
margin: 24px 0 0 !important;
|
||||||
|
background: #ffffff !important;
|
||||||
|
border: 1px solid var(--slate-200) !important;
|
||||||
|
border-radius: var(--radius-md) !important;
|
||||||
|
box-shadow: var(--shadow-card);
|
||||||
|
}
|
||||||
|
|
||||||
|
.submit-row p {
|
||||||
|
margin: 0 !important;
|
||||||
|
}
|
||||||
|
|
||||||
|
.submit-row p.deletelink-box {
|
||||||
|
float: none !important;
|
||||||
|
margin-right: auto !important;
|
||||||
|
}
|
||||||
|
|
||||||
|
.submit-row a.deletelink {
|
||||||
|
display: inline-flex !important;
|
||||||
|
align-items: center;
|
||||||
|
justify-content: center;
|
||||||
|
height: auto !important;
|
||||||
|
min-height: 38px;
|
||||||
|
line-height: 1.4 !important;
|
||||||
|
padding: 10px 20px !important;
|
||||||
|
border-radius: 8px !important;
|
||||||
|
color: #ffffff !important;
|
||||||
|
background: var(--danger) !important;
|
||||||
|
text-decoration: none !important;
|
||||||
|
font-weight: 600;
|
||||||
|
font-size: 13px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.submit-row a.deletelink:hover,
|
||||||
|
.submit-row a.deletelink:focus {
|
||||||
|
background: #dc2626 !important;
|
||||||
|
}
|
||||||
|
|
||||||
|
.submit-row input,
|
||||||
|
.submit-row a.button,
|
||||||
|
.submit-row .button {
|
||||||
|
height: auto !important;
|
||||||
|
min-height: 38px;
|
||||||
|
line-height: 1.4 !important;
|
||||||
|
padding: 10px 20px !important;
|
||||||
|
margin: 0 !important;
|
||||||
|
border-radius: 8px !important;
|
||||||
|
font-size: 13px !important;
|
||||||
|
font-weight: 600 !important;
|
||||||
|
text-transform: none !important;
|
||||||
|
cursor: pointer;
|
||||||
|
}
|
||||||
|
|
||||||
|
.submit-row input.default {
|
||||||
|
background: var(--primary) !important;
|
||||||
|
border-color: var(--primary) !important;
|
||||||
|
color: #ffffff !important;
|
||||||
|
}
|
||||||
|
|
||||||
|
.submit-row input[name="_addanother"],
|
||||||
|
.submit-row input[name="_continue"],
|
||||||
|
.submit-row input[name="_saveasnew"] {
|
||||||
|
background: #ffffff !important;
|
||||||
|
color: var(--slate-700) !important;
|
||||||
|
border: 1px solid var(--slate-300) !important;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* 双栏选择器 */
|
||||||
|
.selector {
|
||||||
|
max-width: 100%;
|
||||||
|
}
|
||||||
|
|
||||||
|
.selector .selector-available h2,
|
||||||
|
.selector .selector-chosen h2 {
|
||||||
|
font-size: 13px;
|
||||||
|
font-weight: 600;
|
||||||
|
color: var(--slate-700);
|
||||||
|
}
|
||||||
|
|
||||||
|
.selector select {
|
||||||
|
max-width: 100%;
|
||||||
|
}
|
||||||
|
|
||||||
|
.selector .selector-filter label {
|
||||||
|
font-size: 12px;
|
||||||
|
color: var(--slate-500);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* 表单模块 */
|
||||||
|
.module h2, fieldset.module h2 {
|
||||||
|
font-size: 14px;
|
||||||
|
font-weight: 700;
|
||||||
|
color: var(--slate-800);
|
||||||
|
background: var(--slate-50) !important;
|
||||||
|
border-bottom: 1px solid var(--slate-200);
|
||||||
|
}
|
||||||
|
|
||||||
|
.form-row label {
|
||||||
|
color: var(--slate-700) !important;
|
||||||
|
font-weight: 600;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Hide messy native elements */
|
||||||
|
#footer, .breadcrumbs, #content-related { display: none !important; }
|
||||||
|
|
||||||
|
@media (max-width: 1280px) {
|
||||||
|
.stats-grid {
|
||||||
|
grid-template-columns: repeat(2, minmax(0, 1fr));
|
||||||
|
}
|
||||||
|
|
||||||
|
.dashboard-main-grid {
|
||||||
|
grid-template-columns: 1fr;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@media (max-width: 768px) {
|
||||||
|
.stats-grid {
|
||||||
|
grid-template-columns: 1fr;
|
||||||
|
}
|
||||||
|
|
||||||
|
#content {
|
||||||
|
padding: 20px !important;
|
||||||
|
}
|
||||||
|
|
||||||
|
.topbar {
|
||||||
|
padding: 0 16px;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/* --- LOGIN PAGE --- */
|
||||||
|
body.login-page {
|
||||||
|
margin: 0;
|
||||||
|
padding: 0;
|
||||||
|
min-height: 100vh;
|
||||||
|
background: var(--slate-100);
|
||||||
|
overflow-x: hidden;
|
||||||
|
}
|
||||||
|
|
||||||
|
.login-shell {
|
||||||
|
display: flex;
|
||||||
|
min-height: 100vh;
|
||||||
|
width: 100%;
|
||||||
|
}
|
||||||
|
|
||||||
|
.login-brand {
|
||||||
|
flex: 1;
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
justify-content: center;
|
||||||
|
padding: 48px;
|
||||||
|
background: linear-gradient(135deg, #4f46e5 0%, #7c3aed 50%, #a855f7 100%);
|
||||||
|
color: #ffffff;
|
||||||
|
position: relative;
|
||||||
|
overflow: hidden;
|
||||||
|
}
|
||||||
|
|
||||||
|
.login-brand::before {
|
||||||
|
content: '';
|
||||||
|
position: absolute;
|
||||||
|
inset: 0;
|
||||||
|
background: radial-gradient(circle at 20% 80%, rgba(255,255,255,0.12) 0%, transparent 50%),
|
||||||
|
radial-gradient(circle at 80% 20%, rgba(255,255,255,0.08) 0%, transparent 40%);
|
||||||
|
pointer-events: none;
|
||||||
|
}
|
||||||
|
|
||||||
|
.login-brand-inner {
|
||||||
|
position: relative;
|
||||||
|
max-width: 420px;
|
||||||
|
z-index: 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
.login-brand-logo {
|
||||||
|
width: 56px;
|
||||||
|
height: 56px;
|
||||||
|
background: rgba(255, 255, 255, 0.2);
|
||||||
|
border-radius: 14px;
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
justify-content: center;
|
||||||
|
font-size: 28px;
|
||||||
|
margin-bottom: 24px;
|
||||||
|
backdrop-filter: blur(4px);
|
||||||
|
}
|
||||||
|
|
||||||
|
.login-brand h1 {
|
||||||
|
font-size: 36px;
|
||||||
|
font-weight: 800;
|
||||||
|
margin: 0 0 8px;
|
||||||
|
letter-spacing: -0.02em;
|
||||||
|
}
|
||||||
|
|
||||||
|
.login-brand-tagline {
|
||||||
|
font-size: 13px;
|
||||||
|
text-transform: uppercase;
|
||||||
|
letter-spacing: 0.1em;
|
||||||
|
opacity: 0.8;
|
||||||
|
margin: 0 0 20px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.login-brand-desc {
|
||||||
|
font-size: 16px;
|
||||||
|
opacity: 0.9;
|
||||||
|
margin: 0 0 32px;
|
||||||
|
line-height: 1.6;
|
||||||
|
}
|
||||||
|
|
||||||
|
.login-brand-features {
|
||||||
|
list-style: none;
|
||||||
|
padding: 0;
|
||||||
|
margin: 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
.login-brand-features li {
|
||||||
|
padding: 10px 0;
|
||||||
|
padding-left: 24px;
|
||||||
|
position: relative;
|
||||||
|
font-size: 14px;
|
||||||
|
opacity: 0.9;
|
||||||
|
}
|
||||||
|
|
||||||
|
.login-brand-features li::before {
|
||||||
|
content: '✓';
|
||||||
|
position: absolute;
|
||||||
|
left: 0;
|
||||||
|
font-weight: 700;
|
||||||
|
}
|
||||||
|
|
||||||
|
.login-panel {
|
||||||
|
flex: 0 0 480px;
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
justify-content: center;
|
||||||
|
padding: 32px;
|
||||||
|
background: var(--slate-50);
|
||||||
|
}
|
||||||
|
|
||||||
|
.login-card {
|
||||||
|
width: 100%;
|
||||||
|
max-width: 400px;
|
||||||
|
background: #ffffff;
|
||||||
|
border-radius: var(--radius-lg);
|
||||||
|
box-shadow: var(--shadow-card);
|
||||||
|
padding: 40px 36px;
|
||||||
|
border: 1px solid var(--slate-200);
|
||||||
|
}
|
||||||
|
|
||||||
|
.login-card-header {
|
||||||
|
margin-bottom: 28px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.login-card-header h2 {
|
||||||
|
font-size: 24px;
|
||||||
|
font-weight: 800;
|
||||||
|
color: var(--slate-900);
|
||||||
|
margin: 0 0 8px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.login-card-header p {
|
||||||
|
font-size: 14px;
|
||||||
|
color: var(--slate-500);
|
||||||
|
margin: 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
.login-error {
|
||||||
|
background: #fef2f2;
|
||||||
|
color: #dc2626;
|
||||||
|
padding: 12px 14px;
|
||||||
|
border-radius: 8px;
|
||||||
|
font-size: 13px;
|
||||||
|
margin-bottom: 20px;
|
||||||
|
border: 1px solid #fecaca;
|
||||||
|
}
|
||||||
|
|
||||||
|
.login-form {
|
||||||
|
margin-bottom: 24px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.login-field {
|
||||||
|
margin-bottom: 20px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.login-field label {
|
||||||
|
display: block;
|
||||||
|
font-size: 13px;
|
||||||
|
font-weight: 600;
|
||||||
|
color: var(--slate-700);
|
||||||
|
margin-bottom: 8px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.login-field input[type="text"],
|
||||||
|
.login-field input[type="password"] {
|
||||||
|
width: 100%;
|
||||||
|
padding: 12px 14px;
|
||||||
|
font-size: 14px;
|
||||||
|
font-family: inherit;
|
||||||
|
border: 1px solid var(--slate-300);
|
||||||
|
border-radius: var(--radius-md);
|
||||||
|
background: #ffffff;
|
||||||
|
color: var(--slate-800);
|
||||||
|
box-sizing: border-box;
|
||||||
|
transition: border-color 0.2s, box-shadow 0.2s;
|
||||||
|
}
|
||||||
|
|
||||||
|
.login-field input[type="text"]:focus,
|
||||||
|
.login-field input[type="password"]:focus {
|
||||||
|
outline: none;
|
||||||
|
border-color: var(--primary);
|
||||||
|
box-shadow: 0 0 0 3px var(--primary-bg);
|
||||||
|
}
|
||||||
|
|
||||||
|
.login-submit {
|
||||||
|
width: 100%;
|
||||||
|
padding: 14px;
|
||||||
|
margin-top: 8px;
|
||||||
|
font-size: 15px;
|
||||||
|
font-weight: 700;
|
||||||
|
font-family: inherit;
|
||||||
|
color: #ffffff;
|
||||||
|
background: linear-gradient(135deg, var(--primary), #7c3aed);
|
||||||
|
border: none;
|
||||||
|
border-radius: var(--radius-md);
|
||||||
|
cursor: pointer;
|
||||||
|
transition: opacity 0.2s, transform 0.15s;
|
||||||
|
}
|
||||||
|
|
||||||
|
.login-submit:hover {
|
||||||
|
opacity: 0.92;
|
||||||
|
transform: translateY(-1px);
|
||||||
|
}
|
||||||
|
|
||||||
|
.login-submit:active {
|
||||||
|
transform: translateY(0);
|
||||||
|
}
|
||||||
|
|
||||||
|
.login-demo {
|
||||||
|
background: var(--primary-bg);
|
||||||
|
border: 1px solid #e0e7ff;
|
||||||
|
border-radius: var(--radius-md);
|
||||||
|
padding: 16px;
|
||||||
|
margin-bottom: 20px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.login-demo-title {
|
||||||
|
font-size: 12px;
|
||||||
|
font-weight: 700;
|
||||||
|
color: var(--primary);
|
||||||
|
margin-bottom: 8px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.login-demo-row {
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
gap: 12px;
|
||||||
|
font-size: 13px;
|
||||||
|
color: var(--slate-600);
|
||||||
|
margin-bottom: 4px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.login-demo-row span {
|
||||||
|
min-width: 48px;
|
||||||
|
color: var(--slate-500);
|
||||||
|
}
|
||||||
|
|
||||||
|
.login-demo-row code {
|
||||||
|
font-family: 'Consolas', monospace;
|
||||||
|
background: rgba(255, 255, 255, 0.8);
|
||||||
|
padding: 2px 8px;
|
||||||
|
border-radius: 4px;
|
||||||
|
font-size: 12px;
|
||||||
|
color: var(--slate-800);
|
||||||
|
}
|
||||||
|
|
||||||
|
.login-demo-divider {
|
||||||
|
height: 1px;
|
||||||
|
background: #e0e7ff;
|
||||||
|
margin: 12px 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
.login-footer-link {
|
||||||
|
text-align: center;
|
||||||
|
}
|
||||||
|
|
||||||
|
.login-footer-link a {
|
||||||
|
font-size: 12px;
|
||||||
|
color: var(--slate-400);
|
||||||
|
text-decoration: none;
|
||||||
|
}
|
||||||
|
|
||||||
|
.login-footer-link a:hover {
|
||||||
|
color: var(--primary);
|
||||||
|
}
|
||||||
|
|
||||||
|
@media (max-width: 900px) {
|
||||||
|
.login-shell {
|
||||||
|
flex-direction: column;
|
||||||
|
}
|
||||||
|
|
||||||
|
.login-brand {
|
||||||
|
flex: none;
|
||||||
|
padding: 32px 24px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.login-brand-inner {
|
||||||
|
max-width: 100%;
|
||||||
|
text-align: center;
|
||||||
|
}
|
||||||
|
|
||||||
|
.login-brand-logo {
|
||||||
|
margin-left: auto;
|
||||||
|
margin-right: auto;
|
||||||
|
}
|
||||||
|
|
||||||
|
.login-brand-features {
|
||||||
|
display: none;
|
||||||
|
}
|
||||||
|
|
||||||
|
.login-panel {
|
||||||
|
flex: 1;
|
||||||
|
padding: 24px 16px 32px;
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,86 @@
|
|||||||
|
(function () {
|
||||||
|
'use strict';
|
||||||
|
|
||||||
|
function ready(fn) {
|
||||||
|
if (document.readyState !== 'loading') {
|
||||||
|
fn();
|
||||||
|
} else {
|
||||||
|
document.addEventListener('DOMContentLoaded', fn);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
function toggleSidebar() {
|
||||||
|
var collapsed = document.body.classList.toggle('sidebar-collapsed');
|
||||||
|
try {
|
||||||
|
localStorage.setItem('erp-sidebar-collapsed', collapsed ? '1' : '0');
|
||||||
|
} catch (e) {}
|
||||||
|
updateCollapseLabel();
|
||||||
|
}
|
||||||
|
|
||||||
|
function updateCollapseLabel() {
|
||||||
|
var btn = document.getElementById('sidebarCollapseBtn');
|
||||||
|
if (!btn) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
var collapsed = document.body.classList.contains('sidebar-collapsed');
|
||||||
|
btn.innerHTML = collapsed
|
||||||
|
? '<i>→</i> 展开菜单'
|
||||||
|
: '<i>←</i> 收起菜单';
|
||||||
|
}
|
||||||
|
|
||||||
|
function restoreSidebarState() {
|
||||||
|
try {
|
||||||
|
if (localStorage.getItem('erp-sidebar-collapsed') === '1') {
|
||||||
|
document.body.classList.add('sidebar-collapsed');
|
||||||
|
}
|
||||||
|
} catch (e) {}
|
||||||
|
updateCollapseLabel();
|
||||||
|
}
|
||||||
|
|
||||||
|
function toggleUserMenu() {
|
||||||
|
var menu = document.getElementById('userDropdown');
|
||||||
|
if (!menu) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
var open = menu.classList.toggle('open');
|
||||||
|
if (open) {
|
||||||
|
document.addEventListener('click', closeUserMenuOutside);
|
||||||
|
} else {
|
||||||
|
document.removeEventListener('click', closeUserMenuOutside);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
function closeUserMenuOutside(e) {
|
||||||
|
var menu = document.getElementById('userDropdown');
|
||||||
|
var profile = document.getElementById('userProfileToggle');
|
||||||
|
if (!menu || !profile) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
if (!menu.contains(e.target) && !profile.contains(e.target)) {
|
||||||
|
menu.classList.remove('open');
|
||||||
|
document.removeEventListener('click', closeUserMenuOutside);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
function bindClick(id, handler) {
|
||||||
|
var el = document.getElementById(id);
|
||||||
|
if (el) {
|
||||||
|
el.addEventListener('click', function (e) {
|
||||||
|
e.preventDefault();
|
||||||
|
e.stopPropagation();
|
||||||
|
handler(e);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
ready(function () {
|
||||||
|
restoreSidebarState();
|
||||||
|
|
||||||
|
bindClick('topbarMenuBtn', toggleSidebar);
|
||||||
|
bindClick('sidebarCollapseBtn', toggleSidebar);
|
||||||
|
bindClick('topbarNotifyBtn', function () {
|
||||||
|
window.location.href = '/admin/workflow/todolist/';
|
||||||
|
});
|
||||||
|
bindClick('userProfileToggle', toggleUserMenu);
|
||||||
|
});
|
||||||
|
})();
|
||||||
+88
-62
@@ -4,6 +4,7 @@
|
|||||||
<head>
|
<head>
|
||||||
<title>{% block title %}{% endblock %}</title>
|
<title>{% block title %}{% endblock %}</title>
|
||||||
<link rel="stylesheet" type="text/css" href="{% block stylesheet %}{% static "admin/css/base.css" %}{% endblock %}" />
|
<link rel="stylesheet" type="text/css" href="{% block stylesheet %}{% static "admin/css/base.css" %}{% endblock %}" />
|
||||||
|
<link rel="stylesheet" type="text/css" href="{% static "css/modern_ui.css" %}" />
|
||||||
{% block extrastyle %}{% endblock %}
|
{% block extrastyle %}{% endblock %}
|
||||||
<!--[if lte IE 7]><link rel="stylesheet" type="text/css" href="{% block stylesheet_ie %}{% static "admin/css/ie.css" %}{% endblock %}" /><![endif]-->
|
<!--[if lte IE 7]><link rel="stylesheet" type="text/css" href="{% block stylesheet_ie %}{% static "admin/css/ie.css" %}{% endblock %}" /><![endif]-->
|
||||||
{% if LANGUAGE_BIDI %}<link rel="stylesheet" type="text/css" href="{% block stylesheet_rtl %}{% static "admin/css/rtl.css" %}{% endblock %}" />{% endif %}
|
{% if LANGUAGE_BIDI %}<link rel="stylesheet" type="text/css" href="{% block stylesheet_rtl %}{% static "admin/css/rtl.css" %}{% endblock %}" />{% endif %}
|
||||||
@@ -20,77 +21,102 @@
|
|||||||
<div id="container">
|
<div id="container">
|
||||||
|
|
||||||
{% if not is_popup %}
|
{% if not is_popup %}
|
||||||
<!-- Header -->
|
<!-- Header (Sidebar) -->
|
||||||
<div id="header">
|
<div id="header">
|
||||||
<div id="branding">
|
<div class="brand-section">
|
||||||
{% block branding %}{% endblock %}
|
<div class="brand-logo">⚡</div>
|
||||||
|
<div class="brand-text">
|
||||||
|
<h1>智捷ERP</h1>
|
||||||
|
<span>SmartJet ERP</span>
|
||||||
|
</div>
|
||||||
</div>
|
</div>
|
||||||
{% block usertools %}
|
|
||||||
{% if has_permission %}
|
<div class="sidebar-nav">
|
||||||
<div id="user-tools">
|
<a href="/admin/" class="nav-item active"><i>🏠</i> 控制面板</a>
|
||||||
<a href="http://code.xinmi.cloud/" target="_blank" style="color: #ffeb3b; font-weight: bold;">新觅源码库</a> /
|
|
||||||
{% block welcome-msg %}
|
<div class="nav-group-label">核心业务</div>
|
||||||
{% trans 'Welcome,' %}
|
<a href="/admin/sale/saleorder/" class="nav-item"><i>📁</i> 销售管理 <span class="arrow">v</span></a>
|
||||||
<strong>{% firstof user.get_short_name user.get_username %}</strong>.
|
<a href="/admin/purchase/purchaseorder/" class="nav-item"><i>🛒</i> 采购管理 <span class="arrow">v</span></a>
|
||||||
{% endblock %}
|
<a href="/admin/invent/inventory/" class="nav-item"><i>📦</i> 库存管理 <span class="arrow">v</span></a>
|
||||||
{% block userlinks %}
|
|
||||||
<a href="/admin/workflow/todolist">{% trans 'workflow todo' %}</a> /
|
<div class="nav-group-label">组织人力</div>
|
||||||
{% if site_url %}
|
<a href="/admin/organ/organization/" class="nav-item"><i>🏢</i> 组织架构</a>
|
||||||
<a href="/admin/basedata/document">{% trans 'document' %}</a> /
|
<a href="/admin/basedata/employee/" class="nav-item"><i>👥</i> 员工档案</a>
|
||||||
{% endif %}
|
|
||||||
{% if user.is_active and user.is_staff %}
|
<div class="nav-group-label">流程协同</div>
|
||||||
{% url 'django-admindocs-docroot' as docsroot %}
|
<a href="/admin/workflow/instance/" class="nav-item"><i>🛡️</i> 审批中心</a>
|
||||||
{% if docsroot %}
|
|
||||||
<a href="{{ docsroot }}">{% trans 'Documentation' %}</a> /
|
|
||||||
{% endif %}
|
|
||||||
{% endif %}
|
|
||||||
{% if user.has_usable_password %}
|
|
||||||
<a href="{% url 'admin:password_change' %}">{% trans 'Change password' %}</a> /
|
|
||||||
{% endif %}
|
|
||||||
<a href="{% url 'admin:logout' %}">{% trans 'Log out' %}</a>
|
|
||||||
{% endblock %}
|
|
||||||
</div>
|
</div>
|
||||||
{% endif %}
|
|
||||||
{% endblock %}
|
<div class="sidebar-footer">
|
||||||
{% block nav-global %}{% endblock %}
|
<a href="/admin/syscfg/site/" class="nav-item"><i>⚙️</i> 设置</a>
|
||||||
|
<button type="button" id="sidebarCollapseBtn" class="nav-item nav-item-btn"><i>←</i> 收起菜单</button>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
{% block usertools %}{% endblock %}
|
||||||
</div>
|
</div>
|
||||||
<!-- END Header -->
|
|
||||||
{% block breadcrumbs %}
|
|
||||||
<div class="breadcrumbs">
|
|
||||||
<a href="{% url 'admin:index' %}">{% trans 'Home' %}</a>
|
|
||||||
{% if title %} › {{ title }}{% endif %}
|
|
||||||
</div>
|
|
||||||
{% endblock %}
|
|
||||||
{% endif %}
|
{% endif %}
|
||||||
|
|
||||||
{% block messages %}
|
<div id="main" {% if is_popup %}style="margin-left: 0; width: 100%;"{% endif %}>
|
||||||
{% if messages %}
|
{% if not is_popup %}
|
||||||
<ul class="messagelist">{% for message in messages %}
|
<div class="topbar">
|
||||||
<li{% if message.tags %} class="{{ message.tags }}"{% endif %}>{{ message|capfirst }}</li>
|
<div class="topbar-left">
|
||||||
{% endfor %}</ul>
|
<button type="button" class="icon-btn" id="topbarMenuBtn" title="切换菜单">☰</button>
|
||||||
{% endif %}
|
<div class="breadcrumb-new">首页 > <span>控制面板</span></div>
|
||||||
{% endblock messages %}
|
</div>
|
||||||
|
<div class="topbar-right">
|
||||||
<!-- Content -->
|
<button type="button" class="icon-btn" id="topbarNotifyBtn" title="待办任务">🔔</button>
|
||||||
<div id="content" class="{% block coltype %}colM{% endblock %}">
|
<div class="user-menu-wrap">
|
||||||
{% block pretitle %}{% endblock %}
|
<button type="button" class="user-profile" id="userProfileToggle" title="用户菜单">
|
||||||
{% block content_title %}{% if title %}<h1>{{ title }}</h1>{% endif %}{% endblock %}
|
<div class="avatar" style="background: url('https://ui-avatars.com/api/?name={{ user.get_short_name|default:"管理员" }}&background=6366f1&color=fff') no-repeat center center; background-size: cover;"></div>
|
||||||
{% block content %}
|
<div class="user-info">
|
||||||
{% block object-tools %}{% endblock %}
|
<span class="user-name">{{ user.get_short_name|default:"管理员" }}</span>
|
||||||
{{ content }}
|
<span class="user-role">系统管理员</span>
|
||||||
{% endblock %}
|
</div>
|
||||||
{% block sidebar %}{% endblock %}
|
<span class="user-caret">▾</span>
|
||||||
<br class="clear" />
|
</button>
|
||||||
</div>
|
<div class="user-dropdown" id="userDropdown">
|
||||||
<!-- END Content -->
|
<a href="{% url 'admin:password_change' %}">修改密码</a>
|
||||||
|
<a href="{% url 'admin:logout' %}">退出登录</a>
|
||||||
{% block footer %}<div id="footer">
|
</div>
|
||||||
<div style="text-align: center; padding: 10px;">
|
</div>
|
||||||
<a href="http://code.xinmi.cloud/" target="_blank" style="color: #666; text-decoration: none;">智捷ERP - 新觅源码库</a>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>{% endblock %}
|
{% endif %}
|
||||||
|
|
||||||
|
{% block messages %}
|
||||||
|
{% if messages %}
|
||||||
|
<ul class="messagelist">{% for message in messages %}
|
||||||
|
<li{% if message.tags %} class="{{ message.tags }}"{% endif %}>{{ message|capfirst }}</li>
|
||||||
|
{% endfor %}</ul>
|
||||||
|
{% endif %}
|
||||||
|
{% endblock messages %}
|
||||||
|
|
||||||
|
<!-- Content -->
|
||||||
|
<div id="content" class="{% block coltype %}colM{% endblock %}">
|
||||||
|
{% block pretitle %}{% endblock %}
|
||||||
|
{% block content_title %}{% if title %}<h1>{{ title }}</h1>{% endif %}{% endblock %}
|
||||||
|
{% block content %}
|
||||||
|
{% block object-tools %}{% endblock %}
|
||||||
|
{{ content }}
|
||||||
|
{% endblock %}
|
||||||
|
{% block sidebar %}{% endblock %}
|
||||||
|
<br class="clear" />
|
||||||
|
</div>
|
||||||
|
<!-- END Content -->
|
||||||
|
|
||||||
|
{% if not is_popup %}
|
||||||
|
{% block footer %}
|
||||||
|
<div id="footer">
|
||||||
|
<div style="text-align: center; padding: 10px;">
|
||||||
|
<a href="http://code.xinmi.cloud/" target="_blank" style="color: #666; text-decoration: none;">智捷ERP - 新觅源码库</a>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
{% endblock %}
|
||||||
|
{% endif %}
|
||||||
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<!-- END Container -->
|
<!-- END Container -->
|
||||||
|
|
||||||
|
<script type="text/javascript" src="{% static "js/modern_ui.js" %}"></script>
|
||||||
</body>
|
</body>
|
||||||
</html>
|
</html>
|
||||||
|
|||||||
+151
-99
@@ -1,110 +1,162 @@
|
|||||||
{% extends "admin/base_site.html" %}
|
{% extends "admin/base_site.html" %}
|
||||||
{% load i18n admin_static %}
|
{% load i18n admin_static %}
|
||||||
|
|
||||||
{% block extrastyle %}{{ block.super }}
|
|
||||||
<link rel="stylesheet" type="text/css" href="{% static "admin/css/dashboard.css" %}" />
|
|
||||||
{% endblock %}
|
|
||||||
|
|
||||||
{% block coltype %}colMS{% endblock %}
|
|
||||||
|
|
||||||
{% block bodyclass %}{{ block.super }} dashboard{% endblock %}
|
|
||||||
|
|
||||||
{% block breadcrumbs %}
|
|
||||||
<div class="breadcrumbs">
|
|
||||||
<a href="{% url 'admin:index' %}">{% trans 'Home' %}</a>
|
|
||||||
{% for app in maxi_app_list %}
|
|
||||||
|
|
||||||
| <a href="{{ app.app_url }}">{{ app.name }}</a>
|
|
||||||
|
|
||||||
{% endfor %}
|
|
||||||
</div>
|
|
||||||
{% endblock %}
|
|
||||||
|
|
||||||
{% block content %}
|
{% block content %}
|
||||||
<div id="content-main">
|
<div id="content-main">
|
||||||
{% if maxi_app_list %}
|
<!-- Row 1: Stats Cards -->
|
||||||
{% for app in maxi_app_list %}
|
<div class="stats-grid">
|
||||||
|
<div class="stat-card">
|
||||||
|
<div class="stat-header">
|
||||||
|
<div class="stat-icon-bg" style="background: #eef2ff; color: #6366f1;">¥</div>
|
||||||
|
<span class="stat-info-icon">ⓘ</span>
|
||||||
|
</div>
|
||||||
|
<div class="stat-label">销售总额</div>
|
||||||
|
<div class="stat-value">¥ 8,231,078</div>
|
||||||
|
<div class="stat-footer">
|
||||||
|
<span class="stat-trend trend-up">较上月 ▲ 12.6%</span>
|
||||||
|
<svg class="sparkline" viewBox="0 0 100 30"><path d="M0,25 Q15,5 30,20 T60,10 T100,25" fill="none" stroke="#6366f1" stroke-width="2"/></svg>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="stat-card">
|
||||||
|
<div class="stat-header">
|
||||||
|
<div class="stat-icon-bg" style="background: #eff6ff; color: #3b82f6;">📋</div>
|
||||||
|
<span class="stat-info-icon">ⓘ</span>
|
||||||
|
</div>
|
||||||
|
<div class="stat-label">待办审批</div>
|
||||||
|
<div class="stat-value">32</div>
|
||||||
|
<div class="stat-footer">
|
||||||
|
<span class="stat-trend trend-down" style="color: #ef4444;">较昨日 ▲ 8</span>
|
||||||
|
<svg class="sparkline" viewBox="0 0 100 30"><path d="M0,15 L20,25 L40,10 L60,20 L80,5 L100,15" fill="none" stroke="#3b82f6" stroke-width="2"/></svg>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="stat-card">
|
||||||
|
<div class="stat-header">
|
||||||
|
<div class="stat-icon-bg" style="background: #fff7ed; color: #f97316;">📦</div>
|
||||||
|
<span class="stat-info-icon">ⓘ</span>
|
||||||
|
</div>
|
||||||
|
<div class="stat-label">库存预警</div>
|
||||||
|
<div class="stat-value">18</div>
|
||||||
|
<div class="stat-footer">
|
||||||
|
<span class="stat-trend trend-down" style="color: #ef4444;">较昨日 ▲ 5</span>
|
||||||
|
<svg class="sparkline" viewBox="0 0 100 30"><path d="M0,25 L30,5 L70,25 L100,10" fill="none" stroke="#f97316" stroke-width="2"/></svg>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="stat-card">
|
||||||
|
<div class="stat-header">
|
||||||
|
<div class="stat-icon-bg" style="background: #f0fdf4; color: #10b981;">🖥️</div>
|
||||||
|
<span class="stat-info-icon">ⓘ</span>
|
||||||
|
</div>
|
||||||
|
<div class="stat-label">系统在线</div>
|
||||||
|
<div class="stat-value">98.6%</div>
|
||||||
|
<div class="stat-footer">
|
||||||
|
<span class="stat-trend trend-up">较昨日 ▲ 0.8%</span>
|
||||||
|
<svg class="sparkline" viewBox="0 0 100 30"><path d="M0,20 L25,15 L50,22 L75,10 L100,12" fill="none" stroke="#10b981" stroke-width="2"/></svg>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
<div class="app-{{ app.app_label }} module">
|
<!-- Row 2: Main Grid -->
|
||||||
<table>
|
<div class="dashboard-main-grid">
|
||||||
<caption>
|
<!-- Operation Logs -->
|
||||||
<a href="{{ app.app_url }}" class="section" title="{% blocktrans with name=app.name %}Models in the {{ name }} application{% endblocktrans %}">{{ app.name }}</a>
|
<div class="module-card">
|
||||||
</caption>
|
<div class="card-title">最近操作日志</div>
|
||||||
{% for model in app.models %}
|
<div class="table-container">
|
||||||
<tr class="model-{{ model.object_name|lower }}">
|
<table>
|
||||||
{% if model.admin_url %}
|
<thead>
|
||||||
<th scope="row"><a href="{{ model.admin_url }}">{{ model.name }}</a></th>
|
<tr>
|
||||||
{% else %}
|
<th>时间</th>
|
||||||
<th scope="row">{{ model.name }}</th>
|
<th>操作人</th>
|
||||||
{% endif %}
|
<th>模块</th>
|
||||||
|
<th>操作类型</th>
|
||||||
{% if model.add_url %}
|
<th>操作内容</th>
|
||||||
<td><a href="{{ model.add_url }}" class="addlink">{% trans 'Add' %}</a></td>
|
<th>IP地址</th>
|
||||||
{% else %}
|
</tr>
|
||||||
<td> </td>
|
</thead>
|
||||||
{% endif %}
|
<tbody>
|
||||||
|
<tr>
|
||||||
{% if model.admin_url %}
|
<td>2025-05-22 10:24:31</td>
|
||||||
<td><a href="{{ model.admin_url }}" class="changelink">{% trans 'Change' %}</a></td>
|
<td>张伟</td>
|
||||||
{% else %}
|
<td>销售管理</td>
|
||||||
<td> </td>
|
<td><span class="badge badge-new">新增</span></td>
|
||||||
{% endif %}
|
<td>新增销售订单 SO-20250522-001</td>
|
||||||
</tr>
|
<td>192.168.1.100</td>
|
||||||
{% endfor %}
|
</tr>
|
||||||
|
<tr>
|
||||||
</table>
|
<td>2025-05-22 10:18:44</td>
|
||||||
|
<td>李娜</td>
|
||||||
|
<td>采购管理</td>
|
||||||
|
<td><span class="badge badge-audit">审核</span></td>
|
||||||
|
<td>审核采购订单 PO-20250522-045</td>
|
||||||
|
<td>192.168.1.101</td>
|
||||||
|
</tr>
|
||||||
|
<tr>
|
||||||
|
<td>2025-05-22 09:56:12</td>
|
||||||
|
<td>王强</td>
|
||||||
|
<td>库存管理</td>
|
||||||
|
<td><span class="badge badge-update">更新</span></td>
|
||||||
|
<td>更新库存调拔单 TB-20250522-009</td>
|
||||||
|
<td>192.168.1.102</td>
|
||||||
|
</tr>
|
||||||
|
<tr>
|
||||||
|
<td>2025-05-22 09:41:07</td>
|
||||||
|
<td>张伟</td>
|
||||||
|
<td>审批中心</td>
|
||||||
|
<td><span class="badge badge-submit">提交</span></td>
|
||||||
|
<td>提交费用报销单 FB-20250522-008</td>
|
||||||
|
<td>192.168.1.100</td>
|
||||||
|
</tr>
|
||||||
|
</tbody>
|
||||||
|
</table>
|
||||||
|
</div>
|
||||||
|
<div style="padding: 20px 32px; border-top: 1px solid var(--slate-50); display: flex; justify-content: space-between; align-items: center; font-size: 12px; color: var(--slate-400);">
|
||||||
|
<span>共 120 条记录</span>
|
||||||
|
<div style="display: flex; gap: 8px;">
|
||||||
|
<span style="width: 24px; height: 24px; background: var(--primary); color: white; display: flex; align-items: center; justify-content: center; border-radius: 4px;">1</span>
|
||||||
|
<span style="width: 24px; height: 24px; display: flex; align-items: center; justify-content: center;">2</span>
|
||||||
|
<span style="width: 24px; height: 24px; display: flex; align-items: center; justify-content: center;">3</span>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
{% endfor %}
|
<!-- Task Sidebar -->
|
||||||
{% else %}
|
<div class="module-card">
|
||||||
<p>{% trans "You don't have permission to edit anything." %}</p>
|
<div class="card-title">
|
||||||
{% endif %}
|
待办任务
|
||||||
</div>
|
<a href="#" style="font-size: 12px; color: var(--primary); text-decoration: none;">更多 ></a>
|
||||||
{% endblock %}
|
</div>
|
||||||
|
<div class="task-list">
|
||||||
{% block sidebar %}
|
<div class="task-item">
|
||||||
<div id="content-related" style="width:18em">
|
<div class="task-icon" style="background: #3b82f6;">📄</div>
|
||||||
<div class="module">
|
<div class="task-content">
|
||||||
<h2><a href="workflow/todolist" style="float:right">更多</a>我的待办</h2>
|
<div class="task-name">费用报销单审批</div>
|
||||||
{% if not todolist %}
|
<div class="task-info">报销人:张伟</div>
|
||||||
<p>无待办任务</p>
|
<span class="priority-tag p-urgent">紧急</span>
|
||||||
{% else %}
|
</div>
|
||||||
<ul class="actionlist">
|
<div class="task-time">10分钟前</div>
|
||||||
{% for todo in todolist%}
|
</div>
|
||||||
<li class="changelink">
|
<div class="task-item">
|
||||||
{{todo.href}}<br/>
|
<div class="task-icon" style="background: #f97316;">🛒</div>
|
||||||
<span class="mini quiet">{{todo.submitter}} {{todo.start_time}}</span>
|
<div class="task-content">
|
||||||
</li>
|
<div class="task-name">采购订单审批</div>
|
||||||
{% endfor %}
|
<div class="task-info">单号:PO-20250522-047</div>
|
||||||
</ul>
|
<span class="priority-tag p-high">高</span>
|
||||||
{% endif %}
|
</div>
|
||||||
</div>
|
<div class="task-time">30分钟前</div>
|
||||||
<div class="module" id="recent-actions-module">
|
</div>
|
||||||
<h2>{% trans 'Recent Actions' %}</h2>
|
<div class="task-item">
|
||||||
<h3>{% trans 'My Actions' %}</h3>
|
<div class="task-icon" style="background: #10b981;">💰</div>
|
||||||
{% load log %}
|
<div class="task-content">
|
||||||
{% get_admin_log 10 as admin_log for_user user %}
|
<div class="task-name">销售订单审批</div>
|
||||||
{% if not admin_log %}
|
<div class="task-info">单号:SO-20250522-004</div>
|
||||||
<p>{% trans 'None available' %}</p>
|
<span class="priority-tag p-medium">中</span>
|
||||||
{% else %}
|
</div>
|
||||||
<ul class="actionlist">
|
<div class="task-time">1小时前</div>
|
||||||
{% for entry in admin_log %}
|
</div>
|
||||||
<li class="{% if entry.is_addition %}addlink{% endif %}{% if entry.is_change %}changelink{% endif %}{% if entry.is_deletion %}deletelink{% endif %}">
|
</div>
|
||||||
{% if entry.is_deletion or not entry.get_admin_url %}
|
<div class="view-all">
|
||||||
{{ entry.object_repr }}
|
<a href="/admin/workflow/todolist/">查看全部待办 →</a>
|
||||||
{% else %}
|
</div>
|
||||||
<a href="{{ entry.get_admin_url }}">{{ entry.object_repr }}</a>
|
</div>
|
||||||
{% endif %}
|
|
||||||
<br/>
|
|
||||||
{% if entry.content_type %}
|
|
||||||
<span class="mini quiet">{% filter capfirst %}{{ entry.content_type }}{% endfilter %}</span>
|
|
||||||
{% else %}
|
|
||||||
<span class="mini quiet">{% trans 'Unknown content' %}</span>
|
|
||||||
{% endif %}
|
|
||||||
</li>
|
|
||||||
{% endfor %}
|
|
||||||
</ul>
|
|
||||||
{% endif %}
|
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
{% endblock %}
|
{% endblock %}
|
||||||
|
|||||||
+65
-130
@@ -1,140 +1,75 @@
|
|||||||
{% extends "admin/base_site.html" %}
|
{% extends "admin/login_base.html" %}
|
||||||
{% load i18n admin_static %}
|
{% load i18n admin_static %}
|
||||||
|
|
||||||
{% block extrastyle %}{{ block.super }}
|
|
||||||
<style>
|
|
||||||
body {
|
|
||||||
background: url('https://images.unsplash.com/photo-1497215728101-856f4ea42174?ixlib=rb-1.2.1&auto=format&fit=crop&w=1950&q=80') no-repeat center center fixed;
|
|
||||||
background-size: cover;
|
|
||||||
display: flex;
|
|
||||||
align-items: center;
|
|
||||||
justify-content: center;
|
|
||||||
height: 100vh;
|
|
||||||
margin: 0;
|
|
||||||
}
|
|
||||||
#container {
|
|
||||||
background: transparent;
|
|
||||||
width: 100%;
|
|
||||||
display: flex;
|
|
||||||
justify-content: center;
|
|
||||||
}
|
|
||||||
#content {
|
|
||||||
background: rgba(255, 255, 255, 0.95);
|
|
||||||
border-radius: 12px;
|
|
||||||
box-shadow: 0 20px 40px rgba(0,0,0,0.3);
|
|
||||||
width: 100%;
|
|
||||||
max-width: 400px;
|
|
||||||
padding: 40px;
|
|
||||||
backdrop-filter: blur(8px);
|
|
||||||
margin: 0;
|
|
||||||
}
|
|
||||||
.login #header, .login .breadcrumbs, .login #footer { display: none; }
|
|
||||||
#content-title { display: none; }
|
|
||||||
.login .form-row { border: none; padding: 12px 0; }
|
|
||||||
.login label { display: block; margin-bottom: 8px; color: #444; font-weight: 600; font-size: 14px; }
|
|
||||||
.login input[type=text], .login input[type=password] {
|
|
||||||
width: 100%;
|
|
||||||
padding: 12px;
|
|
||||||
border: 1px solid #ddd;
|
|
||||||
border-radius: 6px;
|
|
||||||
box-sizing: border-box;
|
|
||||||
font-size: 14px;
|
|
||||||
transition: border-color 0.3s;
|
|
||||||
}
|
|
||||||
.login input[type=text]:focus, .login input[type=password]:focus {
|
|
||||||
border-color: #007bff;
|
|
||||||
outline: none;
|
|
||||||
}
|
|
||||||
.submit-row { margin-top: 24px; text-align: center; }
|
|
||||||
.submit-row input {
|
|
||||||
background: #007bff;
|
|
||||||
color: white;
|
|
||||||
padding: 12px 0;
|
|
||||||
width: 100%;
|
|
||||||
border: none;
|
|
||||||
border-radius: 6px;
|
|
||||||
cursor: pointer;
|
|
||||||
font-size: 16px;
|
|
||||||
font-weight: 600;
|
|
||||||
transition: background 0.3s, transform 0.2s;
|
|
||||||
}
|
|
||||||
.submit-row input:hover {
|
|
||||||
background: #0056b3;
|
|
||||||
transform: translateY(-1px);
|
|
||||||
}
|
|
||||||
.submit-row input:active {
|
|
||||||
transform: translateY(0);
|
|
||||||
}
|
|
||||||
.default-account {
|
|
||||||
margin-top: 30px;
|
|
||||||
padding: 15px;
|
|
||||||
background: #f0f7ff;
|
|
||||||
border-left: 4px solid #007bff;
|
|
||||||
border-radius: 4px;
|
|
||||||
font-size: 13px;
|
|
||||||
color: #555;
|
|
||||||
line-height: 1.6;
|
|
||||||
}
|
|
||||||
.brand-logo {
|
|
||||||
text-align: center;
|
|
||||||
margin-bottom: 30px;
|
|
||||||
}
|
|
||||||
.brand-logo h1 {
|
|
||||||
font-size: 28px;
|
|
||||||
color: #333;
|
|
||||||
margin: 0;
|
|
||||||
letter-spacing: 1px;
|
|
||||||
}
|
|
||||||
.errornote {
|
|
||||||
background: #fff5f5;
|
|
||||||
color: #e53e3e;
|
|
||||||
padding: 10px;
|
|
||||||
border-radius: 4px;
|
|
||||||
font-size: 13px;
|
|
||||||
margin-bottom: 20px;
|
|
||||||
border: 1px solid #feb2b2;
|
|
||||||
}
|
|
||||||
</style>
|
|
||||||
{% endblock %}
|
|
||||||
|
|
||||||
{% block content %}
|
{% block content %}
|
||||||
<div id="content-main">
|
<div class="login-shell">
|
||||||
<div class="brand-logo">
|
<div class="login-brand">
|
||||||
<h1>智捷ERP</h1>
|
<div class="login-brand-inner">
|
||||||
<p style="color: #666; margin-top: 5px;">高效管理 · 企业互联</p>
|
<div class="login-brand-logo">⚡</div>
|
||||||
|
<h1>智捷ERP</h1>
|
||||||
|
<p class="login-brand-tagline">SmartJet ERP</p>
|
||||||
|
<p class="login-brand-desc">高效管理 · 智能协同 · 企业互联</p>
|
||||||
|
<ul class="login-brand-features">
|
||||||
|
<li>销售 / 采购 / 库存一体化</li>
|
||||||
|
<li>组织架构与审批流程</li>
|
||||||
|
<li>数据驱动经营决策</li>
|
||||||
|
</ul>
|
||||||
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
{% if form.errors and not form.non_field_errors %}
|
|
||||||
<p class="errornote">
|
|
||||||
{% if form.errors.items|length == 1 %}{% trans "Please correct the error below." %}{% else %}{% trans "Please correct the errors below." %}{% endif %}
|
|
||||||
</p>
|
|
||||||
{% endif %}
|
|
||||||
|
|
||||||
{% if form.non_field_errors %}
|
<div class="login-panel">
|
||||||
{% for error in form.non_field_errors %}
|
<div class="login-card">
|
||||||
<p class="errornote">
|
<div class="login-card-header">
|
||||||
{{ error }}
|
<h2>欢迎登录</h2>
|
||||||
</p>
|
<p>请输入您的账号和密码</p>
|
||||||
{% endfor %}
|
</div>
|
||||||
{% endif %}
|
|
||||||
|
|
||||||
<form action="{{ app_path }}" method="post" id="login-form">{% csrf_token %}
|
{% if form.errors and not form.non_field_errors %}
|
||||||
<div class="form-row">
|
<div class="login-error">
|
||||||
{{ form.username.label_tag }} {{ form.username }}
|
{% if form.errors.items|length == 1 %}请修正以下错误。{% else %}请修正以下错误。{% endif %}
|
||||||
</div>
|
</div>
|
||||||
<div class="form-row">
|
{% endif %}
|
||||||
{{ form.password.label_tag }} {{ form.password }}
|
|
||||||
<input type="hidden" name="next" value="{{ next }}" />
|
|
||||||
</div>
|
|
||||||
<div class="submit-row">
|
|
||||||
<input type="submit" value="{% trans 'Log in' %}" />
|
|
||||||
</div>
|
|
||||||
</form>
|
|
||||||
|
|
||||||
<div class="default-account">
|
{% if form.non_field_errors %}
|
||||||
<strong style="color: #007bff;">演示账号</strong><br>
|
{% for error in form.non_field_errors %}
|
||||||
用户名:admin<br>
|
<div class="login-error">{{ error }}</div>
|
||||||
密 码:admin
|
{% endfor %}
|
||||||
|
{% endif %}
|
||||||
|
|
||||||
|
{% if user.is_authenticated %}
|
||||||
|
<div class="login-error">
|
||||||
|
您已以 {{ user.get_username }} 登录,但无权访问此页面。请使用其他账号登录。
|
||||||
|
</div>
|
||||||
|
{% endif %}
|
||||||
|
|
||||||
|
<form action="{{ app_path }}" method="post" id="login-form" class="login-form">
|
||||||
|
{% csrf_token %}
|
||||||
|
<div class="login-field">
|
||||||
|
<label for="id_username">用户名</label>
|
||||||
|
{{ form.username }}
|
||||||
|
</div>
|
||||||
|
<div class="login-field">
|
||||||
|
<label for="id_password">密码</label>
|
||||||
|
{{ form.password }}
|
||||||
|
<input type="hidden" name="next" value="{{ next }}" />
|
||||||
|
</div>
|
||||||
|
<button type="submit" class="login-submit">登 录</button>
|
||||||
|
</form>
|
||||||
|
|
||||||
|
<div class="login-demo">
|
||||||
|
<div class="login-demo-title">演示账号</div>
|
||||||
|
<div class="login-demo-row">
|
||||||
|
<span>用户名</span><code>xinmi_admin</code>
|
||||||
|
</div>
|
||||||
|
<div class="login-demo-row">
|
||||||
|
<span>密 码</span><code>admin123456</code>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="login-footer-link">
|
||||||
|
<a href="http://code.xinmi.cloud/" target="_blank" rel="noopener">智捷ERP · 新觅源码库</a>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
{% endblock %}
|
{% endblock %}
|
||||||
|
|||||||
@@ -0,0 +1,13 @@
|
|||||||
|
{% load i18n admin_static %}<!DOCTYPE html>
|
||||||
|
<html lang="zh-hans">
|
||||||
|
<head>
|
||||||
|
<meta charset="utf-8">
|
||||||
|
<meta name="viewport" content="width=device-width, initial-scale=1">
|
||||||
|
<title>{% block title %}登录 | 智捷ERP{% endblock %}</title>
|
||||||
|
<link rel="stylesheet" type="text/css" href="{% static "css/modern_ui.css" %}" />
|
||||||
|
{% block extrastyle %}{% endblock %}
|
||||||
|
</head>
|
||||||
|
<body class="login-page">
|
||||||
|
{% block content %}{% endblock %}
|
||||||
|
</body>
|
||||||
|
</html>
|
||||||
+1
-1
@@ -109,7 +109,7 @@ class Instance(models.Model):
|
|||||||
index_weight = 3
|
index_weight = 3
|
||||||
code = models.CharField(_("code"),blank=True,null=True,max_length=const.DB_CHAR_CODE_10)
|
code = models.CharField(_("code"),blank=True,null=True,max_length=const.DB_CHAR_CODE_10)
|
||||||
modal = models.ForeignKey(Modal,verbose_name=_("workflow model"))
|
modal = models.ForeignKey(Modal,verbose_name=_("workflow model"))
|
||||||
object_id = models.PositiveIntegerField("object id")
|
object_id = models.PositiveIntegerField(_("object id"))
|
||||||
starter = models.ForeignKey(User,verbose_name=_("start user"),related_name="starter")
|
starter = models.ForeignKey(User,verbose_name=_("start user"),related_name="starter")
|
||||||
start_time = models.DateTimeField(_("start time"),auto_now_add=True)
|
start_time = models.DateTimeField(_("start time"),auto_now_add=True)
|
||||||
approved_time = models.DateTimeField(_("approved time"),blank=True,null=True)
|
approved_time = models.DateTimeField(_("approved time"),blank=True,null=True)
|
||||||
|
|||||||
Reference in New Issue
Block a user