fix bug
This commit is contained in:
parent
daf4530753
commit
c4455def3f
@ -616,3 +616,71 @@ input[type="date"]::-webkit-calendar-picker-indicator:hover{
|
|||||||
[data-theme="light"] .watermark-text {
|
[data-theme="light"] .watermark-text {
|
||||||
opacity: 0.06;
|
opacity: 0.06;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* 工单页面样式 */
|
||||||
|
.page-container{max-width:100%;margin:0 auto}
|
||||||
|
.page-header{margin-bottom:24px}
|
||||||
|
.page-header h1{font-size:24px;font-weight:700;margin:0;color:var(--text)}
|
||||||
|
|
||||||
|
.filter-section{background:var(--surface);border:1px solid var(--border);border-radius:12px;padding:20px;margin-bottom:20px}
|
||||||
|
.filter-row{display:flex;gap:16px;align-items:flex-end;flex-wrap:wrap}
|
||||||
|
.filter-item{flex:1;min-width:200px;display:flex;flex-direction:column;gap:6px}
|
||||||
|
.filter-item label{color:var(--text-2);font-size:13px;font-weight:500}
|
||||||
|
.filter-item input,.filter-item select{background:var(--bg);color:var(--text);border:1px solid var(--border);border-radius:8px;padding:10px;font-size:14px}
|
||||||
|
.filter-item input:focus,.filter-item select:focus{outline:2px solid var(--primary);border-color:var(--primary)}
|
||||||
|
.filter-actions{display:flex;gap:8px;align-items:flex-end}
|
||||||
|
.filter-actions .btn{padding:10px 20px;font-size:14px}
|
||||||
|
|
||||||
|
.table-container{background:var(--surface);border:1px solid var(--border);border-radius:12px;overflow:hidden;margin-bottom:20px}
|
||||||
|
.data-table{width:100%;border-collapse:collapse;font-size:13px}
|
||||||
|
.data-table thead{background:var(--surface-2);position:sticky;top:0;z-index:1}
|
||||||
|
.data-table th{padding:12px 16px;text-align:left;font-weight:600;color:var(--text);border-bottom:2px solid var(--border);white-space:nowrap}
|
||||||
|
.data-table td{padding:12px 16px;border-bottom:1px solid var(--border);color:var(--text-2)}
|
||||||
|
.data-table tbody tr:hover{background:rgba(79,140,255,.08)}
|
||||||
|
.data-table tbody tr:last-child td{border-bottom:none}
|
||||||
|
|
||||||
|
.status-badge{display:inline-block;padding:4px 12px;border-radius:12px;font-size:12px;font-weight:500}
|
||||||
|
.status-badge.status-pending{background:rgba(245,158,11,.2);color:#f59e0b}
|
||||||
|
.status-badge.status-processing{background:rgba(79,140,255,.2);color:#4f8cff}
|
||||||
|
.status-badge.status-completed{background:rgba(34,197,94,.2);color:#22c55e}
|
||||||
|
.status-badge.status-cancelled{background:rgba(239,68,68,.2);color:#ef4444}
|
||||||
|
|
||||||
|
.btn-icon{background:transparent;border:none;cursor:pointer;font-size:16px;padding:4px 8px;border-radius:6px;transition:background 0.2s}
|
||||||
|
.btn-icon:hover{background:rgba(79,140,255,.15)}
|
||||||
|
|
||||||
|
.pagination{display:flex;align-items:center;justify-content:center;gap:16px;padding:16px}
|
||||||
|
.pagination .btn{min-width:80px}
|
||||||
|
.pagination .btn:disabled{opacity:0.5;cursor:not-allowed}
|
||||||
|
#page-info{color:var(--text-2);font-size:14px}
|
||||||
|
|
||||||
|
/* 弹窗样式 */
|
||||||
|
.modal{position:fixed;top:0;left:0;width:100%;height:100%;background:rgba(0,0,0,0.6);display:flex;align-items:center;justify-content:center;z-index:1000;backdrop-filter:blur(4px)}
|
||||||
|
.modal-content{background:var(--surface);border:1px solid var(--border);border-radius:16px;width:90%;max-width:600px;max-height:90vh;overflow:hidden;display:flex;flex-direction:column;box-shadow:0 20px 60px rgba(0,0,0,0.3)}
|
||||||
|
.modal-header{display:flex;align-items:center;justify-content:space-between;padding:20px 24px;border-bottom:1px solid var(--border)}
|
||||||
|
.modal-header h2{margin:0;font-size:20px;font-weight:700;color:var(--text)}
|
||||||
|
.modal-close{background:transparent;border:none;font-size:28px;color:var(--text-2);cursor:pointer;padding:0;width:32px;height:32px;display:flex;align-items:center;justify-content:center;border-radius:6px;transition:all 0.2s}
|
||||||
|
.modal-close:hover{background:rgba(239,68,68,0.15);color:var(--danger)}
|
||||||
|
.modal-body{padding:24px;overflow-y:auto;flex:1}
|
||||||
|
.modal-footer{display:flex;gap:12px;justify-content:flex-end;padding:16px 24px;border-top:1px solid var(--border)}
|
||||||
|
|
||||||
|
/* 表单网格 */
|
||||||
|
.form-grid{display:grid;grid-template-columns:repeat(2,1fr);gap:16px}
|
||||||
|
.form-grid .field.full-width{grid-column:1 / -1}
|
||||||
|
.field .required{color:var(--danger);margin-left:2px}
|
||||||
|
.field textarea{resize:vertical;font-family:inherit}
|
||||||
|
|
||||||
|
/* 页面头部样式 */
|
||||||
|
.page-header{display:flex;align-items:center;justify-content:space-between;margin-bottom:24px}
|
||||||
|
|
||||||
|
/* 状态徽章 - 已下发为绿色 */
|
||||||
|
.status-badge.status-issued{background:rgba(34,197,94,.2);color:#22c55e}
|
||||||
|
|
||||||
|
/* 状态徽章 - 已确认为橘黄色 */
|
||||||
|
.status-badge.status-confirmed{background:rgba(251,146,60,.2);color:#fb923c}
|
||||||
|
|
||||||
|
/* 删除按钮样式 */
|
||||||
|
.btn-icon.btn-danger:hover{background:rgba(239,68,68,.15);color:var(--danger)}
|
||||||
|
|
||||||
|
/* 确认按钮样式 */
|
||||||
|
.btn-icon.btn-confirm{color:#fb923c}
|
||||||
|
.btn-icon.btn-confirm:hover{background:rgba(251,146,60,.15);color:#fb923c}
|
||||||
|
|||||||
@ -74,6 +74,22 @@
|
|||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
<div class="nav-group">
|
||||||
|
<div class="nav-group-title">生产管理</div>
|
||||||
|
<div class="nav-item has-children" data-expand="production-mgmt">
|
||||||
|
<button class="nav-item-btn">
|
||||||
|
<span class="icon">📋</span>
|
||||||
|
<span class="text">生产管理</span>
|
||||||
|
<span class="caret">▸</span>
|
||||||
|
</button>
|
||||||
|
<div class="nav-children" data-parent="production-mgmt">
|
||||||
|
<a href="#/production-mgmt/work-order" class="nav-child" data-route="production-mgmt-work-order">
|
||||||
|
<span class="child-icon">📝</span>
|
||||||
|
<span>生产工单下发中心</span>
|
||||||
|
</a>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
<div class="nav-group">
|
<div class="nav-group">
|
||||||
<div class="nav-group-title">扩展采集</div>
|
<div class="nav-group-title">扩展采集</div>
|
||||||
<div class="nav-item has-children" data-expand="collect">
|
<div class="nav-item has-children" data-expand="collect">
|
||||||
@ -188,6 +204,7 @@
|
|||||||
<script src="./js/components/personnel.js"></script>
|
<script src="./js/components/personnel.js"></script>
|
||||||
<script src="./js/components/qa.js"></script>
|
<script src="./js/components/qa.js"></script>
|
||||||
<script src="./js/components/production.js"></script>
|
<script src="./js/components/production.js"></script>
|
||||||
|
<script src="./js/components/work-order.js"></script>
|
||||||
<script src="./js/components/export.js"></script>
|
<script src="./js/components/export.js"></script>
|
||||||
<script src="./js/components/settings.js"></script>
|
<script src="./js/components/settings.js"></script>
|
||||||
<script src="./js/components/notifications.js"></script>
|
<script src="./js/components/notifications.js"></script>
|
||||||
|
|||||||
@ -90,8 +90,8 @@
|
|||||||
document.getElementById('overlay').classList.add('hidden');
|
document.getElementById('overlay').classList.add('hidden');
|
||||||
updateUserDisplay(currentUser);
|
updateUserDisplay(currentUser);
|
||||||
|
|
||||||
// 初始化通知系统(仅对超级管理员)
|
// 初始化通知系统(超级管理员和管理员)
|
||||||
if (currentUser && currentUser.role === 'superadmin' && window.NotificationSystem) {
|
if (currentUser && (currentUser.role === 'superadmin' || currentUser.role === 'admin') && window.NotificationSystem) {
|
||||||
window.NotificationSystem.init();
|
window.NotificationSystem.init();
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
@ -102,8 +102,8 @@
|
|||||||
currentUser = user;
|
currentUser = user;
|
||||||
updateUserDisplay(user);
|
updateUserDisplay(user);
|
||||||
|
|
||||||
// 初始化通知系统(仅对超级管理员)
|
// 初始化通知系统(超级管理员和管理员)
|
||||||
if (user && user.role === 'superadmin' && window.NotificationSystem) {
|
if (user && (user.role === 'superadmin' || user.role === 'admin') && window.NotificationSystem) {
|
||||||
window.NotificationSystem.init();
|
window.NotificationSystem.init();
|
||||||
}
|
}
|
||||||
}).catch(()=>{});
|
}).catch(()=>{});
|
||||||
|
|||||||
@ -47,7 +47,8 @@
|
|||||||
'批量上传不良明细文件': '批量上传了不良明细',
|
'批量上传不良明细文件': '批量上传了不良明细',
|
||||||
'上传返修记录': '上传了返修记录',
|
'上传返修记录': '上传了返修记录',
|
||||||
'上传良/不良统计': '上传了良/不良统计',
|
'上传良/不良统计': '上传了良/不良统计',
|
||||||
'上传不良明细': '上传了不良明细'
|
'上传不良明细': '上传了不良明细',
|
||||||
|
'添加工单': '添加了新工单'
|
||||||
};
|
};
|
||||||
return actionMap[action] || action;
|
return actionMap[action] || action;
|
||||||
}
|
}
|
||||||
@ -148,9 +149,9 @@
|
|||||||
try {
|
try {
|
||||||
// 检查用户角色
|
// 检查用户角色
|
||||||
const user = await API.me();
|
const user = await API.me();
|
||||||
if (user.role !== 'superadmin') {
|
if (user.role !== 'superadmin' && user.role !== 'admin') {
|
||||||
console.log('[Notifications] 非超级管理员,不显示通知');
|
console.log('[Notifications] 非管理员,不显示通知');
|
||||||
return; // 只有超级管理员才显示通知铃铛
|
return; // 超级管理员和管理员才显示通知铃铛
|
||||||
}
|
}
|
||||||
|
|
||||||
// 显示通知铃铛
|
// 显示通知铃铛
|
||||||
|
|||||||
@ -92,6 +92,8 @@ const Router = (() => {
|
|||||||
personnel: '人员信息',
|
personnel: '人员信息',
|
||||||
qa: '质检报告',
|
qa: '质检报告',
|
||||||
production: '时间记录',
|
production: '时间记录',
|
||||||
|
'production-mgmt': '生产管理',
|
||||||
|
'work-order': '生产工单下发中心',
|
||||||
export: '导出',
|
export: '导出',
|
||||||
settings: '设置'
|
settings: '设置'
|
||||||
};
|
};
|
||||||
|
|||||||
289
server/app.py
289
server/app.py
@ -142,6 +142,26 @@ def init_db():
|
|||||||
uploader TEXT,
|
uploader TEXT,
|
||||||
ts TEXT
|
ts TEXT
|
||||||
)''')
|
)''')
|
||||||
|
c.execute('''CREATE TABLE IF NOT EXISTS work_orders(
|
||||||
|
id INTEGER PRIMARY KEY AUTOINCREMENT,
|
||||||
|
factory TEXT NOT NULL,
|
||||||
|
order_no TEXT NOT NULL,
|
||||||
|
product_model TEXT,
|
||||||
|
order_qty INTEGER NOT NULL,
|
||||||
|
production_start_time TEXT,
|
||||||
|
production_end_time TEXT,
|
||||||
|
status TEXT DEFAULT 'issued',
|
||||||
|
status_text TEXT DEFAULT '已下发',
|
||||||
|
remark TEXT,
|
||||||
|
created_by TEXT,
|
||||||
|
created_at TEXT,
|
||||||
|
updated_at TEXT
|
||||||
|
)''')
|
||||||
|
# 为已存在的表添加列(如果不存在)
|
||||||
|
try:
|
||||||
|
c.execute('ALTER TABLE work_orders ADD COLUMN product_model TEXT')
|
||||||
|
except Exception:
|
||||||
|
pass # 列已存在
|
||||||
conn.commit()
|
conn.commit()
|
||||||
# create default admin
|
# create default admin
|
||||||
c.execute('SELECT id FROM users WHERE username=?', ('admin',))
|
c.execute('SELECT id FROM users WHERE username=?', ('admin',))
|
||||||
@ -219,6 +239,48 @@ def notify_superadmin(action, detail=''):
|
|||||||
pass
|
pass
|
||||||
|
|
||||||
|
|
||||||
|
def notify_admins(action, detail=''):
|
||||||
|
"""为管理员创建通知(超级管理员操作时使用)"""
|
||||||
|
try:
|
||||||
|
user_id = session.get('user_id')
|
||||||
|
if not user_id:
|
||||||
|
return
|
||||||
|
|
||||||
|
conn = get_db()
|
||||||
|
c = conn.cursor()
|
||||||
|
|
||||||
|
# 获取当前用户信息
|
||||||
|
c.execute('SELECT username, role FROM users WHERE id=?', (user_id,))
|
||||||
|
user = c.fetchone()
|
||||||
|
if not user:
|
||||||
|
conn.close()
|
||||||
|
return
|
||||||
|
|
||||||
|
# 只有超级管理员的操作才通知管理员
|
||||||
|
if user['role'] != 'superadmin':
|
||||||
|
conn.close()
|
||||||
|
return
|
||||||
|
|
||||||
|
# 为所有管理员创建通知
|
||||||
|
c.execute('SELECT id FROM users WHERE role=?', ('admin',))
|
||||||
|
admins = c.fetchall()
|
||||||
|
|
||||||
|
# 使用北京时间(UTC+8)
|
||||||
|
from datetime import timezone, timedelta
|
||||||
|
beijing_tz = timezone(timedelta(hours=8))
|
||||||
|
now = datetime.now(beijing_tz).isoformat()
|
||||||
|
|
||||||
|
for admin in admins:
|
||||||
|
c.execute('INSERT INTO notifications(user_id, username, action, detail, ts, read) VALUES(?,?,?,?,?,?)', (
|
||||||
|
admin['id'], user['username'], action, detail, now, 0
|
||||||
|
))
|
||||||
|
|
||||||
|
conn.commit()
|
||||||
|
conn.close()
|
||||||
|
except Exception:
|
||||||
|
pass
|
||||||
|
|
||||||
|
|
||||||
def get_redis():
|
def get_redis():
|
||||||
global _redis_client
|
global _redis_client
|
||||||
if not redis:
|
if not redis:
|
||||||
@ -365,6 +427,7 @@ def login():
|
|||||||
return jsonify({'error': 'invalid credentials'}), 400
|
return jsonify({'error': 'invalid credentials'}), 400
|
||||||
session['user_id'] = row['id']
|
session['user_id'] = row['id']
|
||||||
session['role'] = row['role']
|
session['role'] = row['role']
|
||||||
|
session['username'] = username
|
||||||
session.permanent = True
|
session.permanent = True
|
||||||
log('login', username)
|
log('login', username)
|
||||||
return jsonify({'ok': True})
|
return jsonify({'ok': True})
|
||||||
@ -1634,7 +1697,7 @@ def clear_module():
|
|||||||
# notifications
|
# notifications
|
||||||
@app.get('/api/notifications')
|
@app.get('/api/notifications')
|
||||||
@require_login
|
@require_login
|
||||||
@require_any_role('superadmin')
|
@require_any_role('superadmin', 'admin')
|
||||||
def get_notifications():
|
def get_notifications():
|
||||||
"""获取当前用户的通知列表"""
|
"""获取当前用户的通知列表"""
|
||||||
user_id = session.get('user_id')
|
user_id = session.get('user_id')
|
||||||
@ -1648,7 +1711,7 @@ def get_notifications():
|
|||||||
|
|
||||||
@app.get('/api/notifications/unread-count')
|
@app.get('/api/notifications/unread-count')
|
||||||
@require_login
|
@require_login
|
||||||
@require_any_role('superadmin')
|
@require_any_role('superadmin', 'admin')
|
||||||
def get_unread_count():
|
def get_unread_count():
|
||||||
"""获取未读通知数量"""
|
"""获取未读通知数量"""
|
||||||
user_id = session.get('user_id')
|
user_id = session.get('user_id')
|
||||||
@ -1662,7 +1725,7 @@ def get_unread_count():
|
|||||||
|
|
||||||
@app.post('/api/notifications/mark-read')
|
@app.post('/api/notifications/mark-read')
|
||||||
@require_login
|
@require_login
|
||||||
@require_any_role('superadmin')
|
@require_any_role('superadmin', 'admin')
|
||||||
def mark_notification_read():
|
def mark_notification_read():
|
||||||
"""标记通知为已读"""
|
"""标记通知为已读"""
|
||||||
data = request.get_json() or {}
|
data = request.get_json() or {}
|
||||||
@ -1682,7 +1745,7 @@ def mark_notification_read():
|
|||||||
|
|
||||||
@app.post('/api/notifications/mark-all-read')
|
@app.post('/api/notifications/mark-all-read')
|
||||||
@require_login
|
@require_login
|
||||||
@require_any_role('superadmin')
|
@require_any_role('superadmin', 'admin')
|
||||||
def mark_all_notifications_read():
|
def mark_all_notifications_read():
|
||||||
"""标记所有通知为已读"""
|
"""标记所有通知为已读"""
|
||||||
user_id = session.get('user_id')
|
user_id = session.get('user_id')
|
||||||
@ -1696,7 +1759,7 @@ def mark_all_notifications_read():
|
|||||||
|
|
||||||
@app.post('/api/notifications/delete-read')
|
@app.post('/api/notifications/delete-read')
|
||||||
@require_login
|
@require_login
|
||||||
@require_any_role('superadmin')
|
@require_any_role('superadmin', 'admin')
|
||||||
def delete_read_notifications():
|
def delete_read_notifications():
|
||||||
"""删除所有已读通知"""
|
"""删除所有已读通知"""
|
||||||
user_id = session.get('user_id')
|
user_id = session.get('user_id')
|
||||||
@ -2543,6 +2606,222 @@ def delete_sop_file(file_id):
|
|||||||
return jsonify({'ok': True, 'message': 'SOP 文件已删除'})
|
return jsonify({'ok': True, 'message': 'SOP 文件已删除'})
|
||||||
|
|
||||||
|
|
||||||
|
# ==================== 工单管理 API ====================
|
||||||
|
|
||||||
|
@app.get('/api/work-orders')
|
||||||
|
@require_login
|
||||||
|
def get_work_orders():
|
||||||
|
"""获取工单列表"""
|
||||||
|
factory = request.args.get('factory', '')
|
||||||
|
order_no = request.args.get('order', '')
|
||||||
|
date = request.args.get('date', '')
|
||||||
|
|
||||||
|
conn = get_db()
|
||||||
|
c = conn.cursor()
|
||||||
|
|
||||||
|
query = 'SELECT * FROM work_orders WHERE 1=1'
|
||||||
|
params = []
|
||||||
|
|
||||||
|
if factory:
|
||||||
|
query += ' AND factory LIKE ?'
|
||||||
|
params.append(f'%{factory}%')
|
||||||
|
|
||||||
|
if order_no:
|
||||||
|
query += ' AND order_no LIKE ?'
|
||||||
|
params.append(f'%{order_no}%')
|
||||||
|
|
||||||
|
if date:
|
||||||
|
query += ' AND (production_start_time LIKE ? OR production_end_time LIKE ?)'
|
||||||
|
params.append(f'{date}%')
|
||||||
|
params.append(f'{date}%')
|
||||||
|
|
||||||
|
query += ' ORDER BY created_at DESC'
|
||||||
|
|
||||||
|
c.execute(query, params)
|
||||||
|
rows = c.fetchall()
|
||||||
|
conn.close()
|
||||||
|
|
||||||
|
orders = []
|
||||||
|
for row in rows:
|
||||||
|
orders.append({
|
||||||
|
'id': str(row['id']),
|
||||||
|
'factory': row['factory'],
|
||||||
|
'orderNo': row['order_no'],
|
||||||
|
'productModel': row['product_model'] if 'product_model' in row.keys() else '',
|
||||||
|
'orderQty': row['order_qty'],
|
||||||
|
'productionStartTime': row['production_start_time'],
|
||||||
|
'productionEndTime': row['production_end_time'],
|
||||||
|
'status': row['status'],
|
||||||
|
'statusText': row['status_text'],
|
||||||
|
'remark': row['remark'],
|
||||||
|
'createdBy': row['created_by'],
|
||||||
|
'createdAt': row['created_at']
|
||||||
|
})
|
||||||
|
|
||||||
|
return jsonify({'ok': True, 'data': orders})
|
||||||
|
|
||||||
|
|
||||||
|
@app.post('/api/work-orders')
|
||||||
|
@require_login
|
||||||
|
@require_any_role('admin','superadmin')
|
||||||
|
def create_work_order():
|
||||||
|
"""创建工单"""
|
||||||
|
data = request.get_json()
|
||||||
|
|
||||||
|
factory = data.get('factory', '').strip()
|
||||||
|
order_no = data.get('orderNo', '').strip()
|
||||||
|
product_model = data.get('productModel', '').strip()
|
||||||
|
order_qty = data.get('orderQty', 0)
|
||||||
|
production_start_time = data.get('productionStartTime', '')
|
||||||
|
production_end_time = data.get('productionEndTime', '')
|
||||||
|
remark = data.get('remark', '').strip()
|
||||||
|
|
||||||
|
if not factory or not order_no or not order_qty:
|
||||||
|
return jsonify({'error': '请填写所有必填项'}), 400
|
||||||
|
|
||||||
|
conn = get_db()
|
||||||
|
c = conn.cursor()
|
||||||
|
|
||||||
|
username = session.get('username', '')
|
||||||
|
now = get_beijing_time()
|
||||||
|
|
||||||
|
c.execute('''INSERT INTO work_orders(
|
||||||
|
factory, order_no, product_model, order_qty, production_start_time, production_end_time,
|
||||||
|
status, status_text, remark, created_by, created_at, updated_at
|
||||||
|
) VALUES(?,?,?,?,?,?,?,?,?,?,?,?)''', (
|
||||||
|
factory, order_no, product_model, order_qty, production_start_time, production_end_time,
|
||||||
|
'issued', '已下发', remark, username, now, now
|
||||||
|
))
|
||||||
|
|
||||||
|
order_id = c.lastrowid
|
||||||
|
conn.commit()
|
||||||
|
conn.close()
|
||||||
|
|
||||||
|
log('create_work_order', f'工单号: {order_no}, 工厂: {factory}, 型号: {product_model}')
|
||||||
|
|
||||||
|
# 如果是超级管理员添加工单,通知所有管理员
|
||||||
|
notify_admins('添加工单', f'工单号: {order_no}, 工厂: {factory}, 数量: {order_qty}')
|
||||||
|
|
||||||
|
return jsonify({'ok': True, 'id': order_id, 'message': '工单创建成功'})
|
||||||
|
|
||||||
|
|
||||||
|
@app.put('/api/work-orders/<int:order_id>')
|
||||||
|
@require_login
|
||||||
|
@require_any_role('admin','superadmin')
|
||||||
|
def update_work_order(order_id):
|
||||||
|
"""更新工单"""
|
||||||
|
data = request.get_json()
|
||||||
|
|
||||||
|
factory = data.get('factory', '').strip()
|
||||||
|
order_no = data.get('orderNo', '').strip()
|
||||||
|
product_model = data.get('productModel', '').strip()
|
||||||
|
order_qty = data.get('orderQty', 0)
|
||||||
|
production_start_time = data.get('productionStartTime', '')
|
||||||
|
production_end_time = data.get('productionEndTime', '')
|
||||||
|
remark = data.get('remark', '').strip()
|
||||||
|
|
||||||
|
if not factory or not order_no or not order_qty:
|
||||||
|
return jsonify({'error': '请填写所有必填项'}), 400
|
||||||
|
|
||||||
|
conn = get_db()
|
||||||
|
c = conn.cursor()
|
||||||
|
|
||||||
|
# 检查工单是否存在
|
||||||
|
c.execute('SELECT id FROM work_orders WHERE id=?', (order_id,))
|
||||||
|
if not c.fetchone():
|
||||||
|
conn.close()
|
||||||
|
return jsonify({'error': '工单不存在'}), 404
|
||||||
|
|
||||||
|
now = get_beijing_time()
|
||||||
|
|
||||||
|
c.execute('''UPDATE work_orders SET
|
||||||
|
factory=?, order_no=?, product_model=?, order_qty=?, production_start_time=?, production_end_time=?,
|
||||||
|
remark=?, updated_at=?
|
||||||
|
WHERE id=?''', (
|
||||||
|
factory, order_no, product_model, order_qty, production_start_time, production_end_time,
|
||||||
|
remark, now, order_id
|
||||||
|
))
|
||||||
|
|
||||||
|
conn.commit()
|
||||||
|
conn.close()
|
||||||
|
|
||||||
|
log('update_work_order', f'工单ID: {order_id}, 工单号: {order_no}, 型号: {product_model}')
|
||||||
|
notify_superadmin('更新工单', f'工单号: {order_no}, 工厂: {factory}, 型号: {product_model}')
|
||||||
|
|
||||||
|
return jsonify({'ok': True, 'message': '工单更新成功'})
|
||||||
|
|
||||||
|
|
||||||
|
@app.delete('/api/work-orders/<int:order_id>')
|
||||||
|
@require_login
|
||||||
|
@require_any_role('admin','superadmin')
|
||||||
|
def delete_work_order(order_id):
|
||||||
|
"""删除工单"""
|
||||||
|
conn = get_db()
|
||||||
|
c = conn.cursor()
|
||||||
|
|
||||||
|
# 获取工单信息用于日志
|
||||||
|
c.execute('SELECT order_no, factory FROM work_orders WHERE id=?', (order_id,))
|
||||||
|
row = c.fetchone()
|
||||||
|
|
||||||
|
if not row:
|
||||||
|
conn.close()
|
||||||
|
return jsonify({'error': '工单不存在'}), 404
|
||||||
|
|
||||||
|
order_no = row['order_no']
|
||||||
|
factory = row['factory']
|
||||||
|
|
||||||
|
c.execute('DELETE FROM work_orders WHERE id=?', (order_id,))
|
||||||
|
conn.commit()
|
||||||
|
conn.close()
|
||||||
|
|
||||||
|
log('delete_work_order', f'工单ID: {order_id}, 工单号: {order_no}')
|
||||||
|
notify_superadmin('删除工单', f'工单号: {order_no}, 工厂: {factory}')
|
||||||
|
|
||||||
|
return jsonify({'ok': True, 'message': '工单删除成功'})
|
||||||
|
|
||||||
|
|
||||||
|
@app.post('/api/work-orders/<int:order_id>/confirm')
|
||||||
|
@require_login
|
||||||
|
@require_any_role('admin','superadmin')
|
||||||
|
def confirm_work_order(order_id):
|
||||||
|
"""确认工单"""
|
||||||
|
conn = get_db()
|
||||||
|
c = conn.cursor()
|
||||||
|
|
||||||
|
# 检查工单是否存在
|
||||||
|
c.execute('SELECT order_no, factory, status FROM work_orders WHERE id=?', (order_id,))
|
||||||
|
row = c.fetchone()
|
||||||
|
|
||||||
|
if not row:
|
||||||
|
conn.close()
|
||||||
|
return jsonify({'error': '工单不存在'}), 404
|
||||||
|
|
||||||
|
order_no = row['order_no']
|
||||||
|
factory = row['factory']
|
||||||
|
current_status = row['status']
|
||||||
|
|
||||||
|
# 如果已经确认,返回提示
|
||||||
|
if current_status == 'confirmed':
|
||||||
|
conn.close()
|
||||||
|
return jsonify({'ok': True, 'message': '工单已确认'})
|
||||||
|
|
||||||
|
# 更新状态为已确认
|
||||||
|
now = get_beijing_time()
|
||||||
|
c.execute('''UPDATE work_orders SET
|
||||||
|
status=?, status_text=?, updated_at=?
|
||||||
|
WHERE id=?''', (
|
||||||
|
'confirmed', '已确认', now, order_id
|
||||||
|
))
|
||||||
|
|
||||||
|
conn.commit()
|
||||||
|
conn.close()
|
||||||
|
|
||||||
|
log('confirm_work_order', f'工单ID: {order_id}, 工单号: {order_no}')
|
||||||
|
notify_superadmin('确认工单', f'工单号: {order_no}, 工厂: {factory}')
|
||||||
|
|
||||||
|
return jsonify({'ok': True, 'message': '工单确认成功'})
|
||||||
|
|
||||||
|
|
||||||
init_db()
|
init_db()
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
Loading…
Reference in New Issue
Block a user