Commit c76c8ec9 by suyuchen

feat(service): 统一将零件费用相关术语更新为配件费用

- 将所有页面中的零件费用标准相关文本替换为配件费用标准 - 更新首页统计卡片中零件费用标准数量标签为配件费用标准数量 - 修改导航菜单中零件费用管理为配件费用管理 - 重命名零件费用标准管理列表页标题为配件费用标准管理 - 更新零件费用标准新增编辑页标题为配件费用标准新增编辑 - 替换标准报价单生成页中零件费用明细为配件费用明细 - 修改标准报价单详情页中零件费用明细为配件费用明细 - 更新服务价格白皮书中
parent 71f3f4aa
<!DOCTYPE html>
<!DOCTYPE html>
......@@ -205,7 +205,7 @@
<div style="font-size: 12px; margin-top: 10px; opacity: 0.8;">已配置标准</div>
</div>
<div class="stat-card success">
<div class="stat-label">件费用标准数量</div>
<div class="stat-label">件费用标准数量</div>
<div class="stat-value">{{ stats.partCount }}</div>
<div style="font-size: 12px; margin-top: 10px; opacity: 0.8;">已配置标准</div>
</div>
......@@ -227,8 +227,8 @@
</a>
<a href="4-零件费用标准管理列表页.html" class="action-btn">
<div class="action-icon">🔧</div>
<div class="action-title">件费用管理</div>
<div class="action-desc">管理件费用标准</div>
<div class="action-title">件费用管理</div>
<div class="action-desc">管理件费用标准</div>
</a>
<a href="6-报价规则配置列表页.html" class="action-btn">
<div class="action-icon">⚙️</div>
......
<!DOCTYPE html>
<!DOCTYPE html>
......@@ -258,20 +258,20 @@
</div>
</div>
<!-- 件费用说明 -->
<!-- 件费用说明 -->
<div class="section">
<div class="section-title">三、件费用说明</div>
<div class="section-title">三、件费用说明</div>
<div class="section-content">
<p>零件费用按照标准零件价格表执行,主要包括:</p>
<p>配件费用按照标准配件价格表执行,主要包括:</p>
<ul style="margin-left: 20px; margin-top: 10px;">
<li>件价格以系统标准价格表为准</li>
<li>件价格可能因市场波动而调整,以实际报价时价格为准</li>
<li>部分件价格含税,部分不含税,具体以报价单为准</li>
<li>件数量以实际使用为准</li>
<li>件价格以系统标准价格表为准</li>
<li>件价格可能因市场波动而调整,以实际报价时价格为准</li>
<li>部分件价格含税,部分不含税,具体以报价单为准</li>
<li>件数量以实际使用为准</li>
</ul>
<div class="info-box" style="margin-top: 20px;">
<div class="info-box-title">件价格查询</div>
<div>详细的零件价格标准请参考系统中的零件费用标准管理模块,或联系客服获取最新价格信息。</div>
<div class="info-box-title">件价格查询</div>
<div>详细的配件价格标准请参考系统中的配件费用标准管理模块,或联系客服获取最新价格信息。</div>
</div>
</div>
</div>
......@@ -322,7 +322,7 @@
<ol style="margin-left: 20px; margin-top: 10px;">
<li><strong>自动匹配规则:</strong>系统根据服务场景(停机/非停机)自动匹配相应的报价规则</li>
<li><strong>人工费用计算:</strong>根据选择的服务类型和技术等级,按照标准价格计算</li>
<li><strong>零件费用计算:</strong>根据实际使用的零件数量和标准价格计算</li>
<li><strong>配件费用计算:</strong>根据实际使用的配件数量和标准价格计算</li>
<li><strong>加急费用:</strong>如适用,按照加急费规则计算并累加</li>
<li><strong>折扣规则:</strong>如适用,按照折扣规则进行减免</li>
<li><strong>最终价格:</strong>所有费用项目相加得出最终报价</li>
......@@ -341,7 +341,7 @@
<p>本白皮书中的所有价格数据均来源于系统价格配置模块:</p>
<ul style="margin-left: 20px; margin-top: 10px;">
<li>人工费用标准:来源于"人工费用标准管理"模块</li>
<li>零件费用标准:来源于"零件费用标准管理"模块</li>
<li>配件费用标准:来源于"配件费用标准管理"模块</li>
<li>报价规则:来源于"报价规则配置"模块</li>
</ul>
<div class="info-box" style="margin-top: 20px;">
......
<!DOCTYPE html>
<!DOCTYPE html>
......@@ -485,7 +485,7 @@
{
quoteNo: 'QT' + (Date.now() - 86400000),
customerName: '示例客户有限公司',
serviceDescription: '服务器故障维修服务,包括硬件检测、故障排查、件更换等',
serviceDescription: '服务器故障维修服务,包括硬件检测、故障排查、件更换等',
quoteDate: new Date(Date.now() - 2 * 86400000).toISOString().split('T')[0],
validUntil: new Date(Date.now() + 28 * 86400000).toISOString().split('T')[0],
status: '有效',
......
<!DOCTYPE html>
<!DOCTYPE html>
......@@ -3,7 +3,7 @@
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>件费用标准管理 - 服务价格标准化管理系统</title>
<title>件费用标准管理 - 服务价格标准化管理系统</title>
<script src="https://unpkg.com/vue@3/dist/vue.global.js"></script>
<style>
* {
......@@ -178,7 +178,7 @@
<div class="container">
<div class="header">
<div class="header-top">
<h1>件费用标准管理</h1>
<h1>件费用标准管理</h1>
<div class="nav-menu">
<a href="1-服务价格标准首页.html" class="nav-item">首页</a>
<a href="2-人工费用标准管理列表页.html" class="nav-item">人工费用</a>
......@@ -190,18 +190,18 @@
<div class="card">
<div class="toolbar">
<div class="card-title">件费用标准列表</div>
<div class="card-title">件费用标准列表</div>
<div style="display: flex; gap: 10px;">
<button class="btn btn-success" @click="handleImport">批量导入</button>
<button class="btn btn-primary" @click="handleAdd">+ 新增</button>
<button class="btn btn-primary" @click="handleAdd">+ 新增</button>
</div>
</div>
<table class="data-table">
<thead>
<tr>
<th>件编号</th>
<th>件名称</th>
<th>件编号</th>
<th>件名称</th>
<th>型号规格</th>
<th>标准单价</th>
<th>单位</th>
......
<!DOCTYPE html>
<!DOCTYPE html>
......@@ -3,7 +3,7 @@
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>件费用标准{{ isEdit ? '编辑' : '新增' }} - 服务价格标准化管理系统</title>
<title>件费用标准{{ isEdit ? '编辑' : '新增' }} - 服务价格标准化管理系统</title>
<script src="https://unpkg.com/vue@3/dist/vue.global.js"></script>
<style>
* {
......@@ -188,7 +188,7 @@
<div id="app">
<div class="container">
<div class="header">
<h1>件费用标准{{ isEdit ? '编辑' : '新增' }}</h1>
<h1>件费用标准{{ isEdit ? '编辑' : '新增' }}</h1>
</div>
<div class="card">
......@@ -196,22 +196,22 @@
<form @submit.prevent="handleSubmit">
<div class="form-row">
<div class="form-group">
<label class="form-label">件编号 <span class="required">*</span></label>
<label class="form-label">件编号 <span class="required">*</span></label>
<input
type="text"
v-model="form.partNo"
class="form-control"
placeholder="请输入件编号"
placeholder="请输入件编号"
required
/>
</div>
<div class="form-group">
<label class="form-label">件名称 <span class="required">*</span></label>
<label class="form-label">件名称 <span class="required">*</span></label>
<input
type="text"
v-model="form.partName"
class="form-control"
placeholder="请输入件名称"
placeholder="请输入件名称"
required
/>
</div>
......
<!DOCTYPE html>
<!DOCTYPE html>
......@@ -382,11 +382,11 @@
<!-- 零件费用明细 -->
<div class="quote-detail">
<div class="quote-detail-title">件费用明细(可选)</div>
<div class="quote-detail-title">件费用明细(可选)</div>
<table class="detail-table">
<thead>
<tr>
<th>件名称</th>
<th>件名称</th>
<th>型号规格</th>
<th>数量</th>
<th>单价</th>
......@@ -398,7 +398,7 @@
<tr v-for="(item, index) in partDetails" :key="index">
<td>
<select v-model="item.partId" class="form-control" @change="updatePartInfo(index)">
<option value="">请选择</option>
<option value="">请选择</option>
<option v-for="part in availableParts" :key="part.id" :value="part.id">
{{ part.partName }}
</option>
......@@ -423,7 +423,7 @@
</tr>
<tr>
<td colspan="6">
<button type="button" class="btn btn-primary btn-small" @click="addPart">+ 添加</button>
<button type="button" class="btn btn-primary btn-small" @click="addPart">+ 添加</button>
</td>
</tr>
</tbody>
......@@ -439,7 +439,7 @@
<td>¥{{ laborSubtotal.toFixed(2) }}</td>
</tr>
<tr>
<td style="text-align: right; font-weight: 600;">件费用小计:</td>
<td style="text-align: right; font-weight: 600;">件费用小计:</td>
<td>¥{{ partSubtotal.toFixed(2) }}</td>
</tr>
<tr class="total-row">
......
<!DOCTYPE html>
<!DOCTYPE html>
......@@ -328,14 +328,14 @@
</table>
</div>
<!-- 件费用明细 -->
<!-- 件费用明细 -->
<div class="detail-section" v-if="partDetails.length > 0">
<div class="detail-section-title">件费用明细</div>
<div class="detail-section-title">件费用明细</div>
<table class="detail-table">
<thead>
<tr>
<th>序号</th>
<th>件名称</th>
<th>件名称</th>
<th>型号规格</th>
<th>数量</th>
<th>单价</th>
......@@ -365,7 +365,7 @@
<td>¥{{ laborSubtotal.toFixed(2) }}</td>
</tr>
<tr v-if="partSubtotal > 0">
<td>件费用小计:</td>
<td>件费用小计:</td>
<td>¥{{ partSubtotal.toFixed(2) }}</td>
</tr>
<tr class="total-row">
......
<!DOCTYPE html>
<!DOCTYPE html>
......@@ -966,3 +966,4 @@
......@@ -30,22 +30,7 @@
<path d="M4 4h12a2 2 0 012 2v8a2 2 0 01-2 2H4a2 2 0 01-2-2V6a2 2 0 012-2z"/>
<path d="M7 9h6M7 12h4"/>
</svg>
<span>设备管理</span>
</div>
<svg class="nav-arrow nav-icon" viewBox="0 0 20 20">
<path d="M7.293 14.707a1 1 0 010-1.414L10.586 10 7.293 6.707a1 1 0 011.414-1.414l4 4a1 1 0 010 1.414l-4 4a1 1 0 01-1.414 0z"/>
</svg>
</div>
<a href="零件管理.html" class="nav-subitem ">
配件管理
</a>
<div class="nav-item has-submenu expanded" onclick="toggleSubmenu(this)">
<div style="display: flex; align-items: center; gap: 12px;">
<svg class="nav-icon" viewBox="0 0 20 20">
<path d="M4 4h12a2 2 0 012 2v8a2 2 0 01-2 2H4a2 2 0 01-2-2V6a2 2 0 012-2z"/>
<path d="M7 9h6M7 12h4"/>
</svg>
<span>服务订单</span>
<span>服务管理</span>
</div>
<svg class="nav-arrow nav-icon" viewBox="0 0 20 20">
<path d="M7.293 14.707a1 1 0 010-1.414L10.586 10 7.293 6.707a1 1 0 011.414-1.414l4 4a1 1 0 010 1.414l-4 4a1 1 0 01-1.414 0z"/>
......@@ -55,11 +40,14 @@
<a href="人工费用标准管理列表页.html" class="nav-subitem ">
人工报价
</a>
<a href="零件管理.html" class="nav-subitem ">
配件报价
</a>
<!--<a href="标准报价单生成.html" class="nav-subitem ">
报价管理
</a>-->
<a href="服务单列表.html" class="nav-subitem ">
服务单列表
服务订单
</a>
</div>
<div class="nav-item has-submenu expanded" onclick="toggleSubmenu(this)">
......@@ -84,6 +72,9 @@
<a href="设备机型.html" class="nav-subitem ">
设备机型
</a>
<a href="配件管理.html" class="nav-subitem ">
配件管理
</a>
</div>
<!-- <div class="nav-item has-submenu expanded" onclick="toggleSubmenu(this)">
<div style="display: flex; align-items: center; gap: 12px;">
......
......@@ -143,6 +143,8 @@ let crawlerSites = [
lastCrawlTime: '2026-01-05T14:30',
nextCrawlTime: '2026-01-06T14:30',
crawlStatus: '正常',
systemUrl: 'https://sys.industrynews.com',
statistics: '数据量: 500条/天, 成功率: 98.5%',
targetDataType: '新闻标题、发布时间、内容摘要',
pageStructureStable: '是',
antiCrawlMechanism: 'IP限制,需使用代理池',
......@@ -165,6 +167,8 @@ let crawlerSites = [
lastCrawlTime: '2026-01-06T10:15',
nextCrawlTime: '2026-01-06T11:15',
crawlStatus: '正常',
systemUrl: 'https://sys.competitoranalysis.com',
statistics: '数据量: 200条/天, 成功率: 92.3%',
targetDataType: '产品价格、功能列表、更新日志',
pageStructureStable: '否',
antiCrawlMechanism: '验证码,需OCR识别',
......@@ -187,6 +191,8 @@ let crawlerSites = [
lastCrawlTime: '',
nextCrawlTime: '',
crawlStatus: '已停用',
systemUrl: 'https://sys.policyregulation.com',
statistics: '数据量: 0条/天, 成功率: 0%',
targetDataType: '',
pageStructureStable: '',
antiCrawlMechanism: '',
......@@ -230,6 +236,8 @@ function renderCrawlerSitesTable() {
<td>${site.crawlFrequency}</td>
<td>${site.lastCrawlTime || '-'}</td>
<td><span class="${crawlStatusClass}">${site.crawlStatus}</span></td>
<td>${site.systemUrl || '-'}</td>
<td>${site.statistics || '-'}</td>
<!-- <td>${site.targetDataType}</td>-->
<!-- <td>${site.antiCrawlMechanism}</td>-->
<!-- <td>${site.负责人}</td>-->
......@@ -297,6 +305,8 @@ function showEditSiteModal(site) {
document.getElementById('collection-plan').value = site.collectionPlan;
document.getElementById('crawl-frequency').value = site.crawlFrequency || '';
document.getElementById('crawl-status').value = site.crawlStatus || '';
document.getElementById('system-url').value = site.systemUrl || '';
document.getElementById('statistics').value = site.statistics || '';
document.getElementById('target-data-type').value = site.targetDataType || '';
document.getElementById('anti-crawl-mechanism').value = site.antiCrawlMechanism || '';
document.getElementById('负责人').value = site.负责人 || '';
......@@ -375,6 +385,8 @@ function saveCrawlerSite() {
const collectionPlan = document.getElementById('collection-plan').value;
const crawlFrequency = document.getElementById('crawl-frequency').value;
const crawlStatus = document.getElementById('crawl-status').value;
const systemUrl = document.getElementById('system-url').value;
const statistics = document.getElementById('statistics').value;
const targetDataType = document.getElementById('target-data-type').value;
const antiCrawlMechanism = document.getElementById('anti-crawl-mechanism').value;
const 负责人 = document.getElementById('负责人').value;
......@@ -411,6 +423,8 @@ function saveCrawlerSite() {
// 计算下次爬取时间(这里只是模拟,实际应根据频率计算)
nextCrawlTime: calculateNextCrawlTime(lastCrawlTime, crawlFrequency),
crawlStatus,
systemUrl,
statistics,
targetDataType,
pageStructureStable: '是', // 默认值,实际应用中可能需要从表单获取
antiCrawlMechanism,
......@@ -439,6 +453,8 @@ function saveCrawlerSite() {
// 计算下次爬取时间(这里只是模拟,实际应根据频率计算)
nextCrawlTime: calculateNextCrawlTime(lastCrawlTime, crawlFrequency),
crawlStatus,
systemUrl,
statistics,
targetDataType,
pageStructureStable: '是', // 默认值
antiCrawlMechanism,
......
<!DOCTYPE html>
<!DOCTYPE html>
......@@ -1783,6 +1783,8 @@
<th>爬取频率</th>
<th>上次爬取时间</th>
<th>爬取状态</th>
<th>预览网址</th>
<th>统计</th>
<!-- <th>目标数据类型</th>-->
<!-- <th>反爬机制</th>-->
<!-- <th>负责人</th>-->
......@@ -1855,6 +1857,13 @@
</select>
</div>
</div>
<div class="form-row">
<div class="form-group">
<label for="PreviewURL">预览网址 *</label>
<input type="text" id="PreviewURL" required placeholder="系统内网址">
</div>
</div>
<!-- <div class="form-row">
<div class="form-group">
<label for="target-data-type">目标数据类型 *</label>
......
<!DOCTYPE html>
<!DOCTYPE html>
......@@ -664,7 +664,7 @@
<!-- 零件费用标准 -->
<div class="card">
<div class="card-header">
<h2 class="card-title">件费用标准</h2>
<h2 class="card-title">件费用标准</h2>
</div>
<table class="price-table">
<thead>
......@@ -826,3 +826,4 @@
<!DOCTYPE html>
<!DOCTYPE html>
......@@ -1685,7 +1685,7 @@
<div class="">
<div class="card-title">
<span>报价单列表 (共 {{ filteredQuotes.length }} 条)</span>
<button class="btn btn-primary btn-sm" style=""><a href="标准报价单生成.html" style="color:#fff;">报价单生成</a></button>
<button class="btn btn-primary btn-sm" style=""><a href="标准报价单生成.html" style="color:#fff;">新增报价单</a></button>
</div>
<!-- 筛选栏 -->
......
<!DOCTYPE html>
<!DOCTYPE html>
......@@ -1781,7 +1781,7 @@
<!-- 零件费用明细 -->
<div class="quote-detail">
<div class="quote-detail-title">件费用明细(可选)</div>
<div class="quote-detail-title">件费用明细(可选)</div>
<table class="detail-table">
<thead>
<tr>
......
<!DOCTYPE html>
<!DOCTYPE html>
<html lang="zh-CN">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title></title>
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/6.4.0/css/all.min.css">
<script src="https://unpkg.com/vue@3/dist/vue.global.js"></script>
<style>
:root {
--primary-color: #1B64F3;
--primary-hover: #1554D3;
--primary-light: #e6f7ff;
--bg-color: #F5F6FA;
--card-bg: #FFFFFF;
--sidebar-bg: #0F172A;
--text-primary: #1A1F36;
--text-secondary: #64748B;
--text-tertiary: #94A3B8;
--text-light: #CBD5E1;
--border-color: #E2E8F0;
--shadow-sm: 0 2px 8px rgba(0, 0, 0, 0.06);
--shadow-md: 0 4px 12px rgba(0, 0, 0, 0.08);
--success-color: #22C55E;
--warning-color: #EAB308;
--error-color: #EF4444;
--sidebar-width: 260px;
--header-height: 64px;
}
* {
margin: 0;
padding: 0;
box-sizing: border-box;
font-family: "PingFang SC", "Microsoft YaHei", sans-serif;
}
body {
font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', 'Roboto', 'Helvetica Neue', Arial, 'PingFang SC', 'Microsoft YaHei', sans-serif;
background-color: var(--bg-color);
color: var(--text-primary);
line-height: 1.6;
overflow-x: hidden;
}
.app-container {
display: flex;
min-height: 100vh;
}
/* 左侧导航栏 */
.sidebar {
position: fixed;
left: 0;
top: 0;
width: var(--sidebar-width);
height: 100vh;
background: var(--sidebar-bg);
border-right: 1px solid rgba(255, 255, 255, 0.1);
overflow-y: auto;
z-index: 1000;
}
.sidebar-logo {
padding: 20px;
border-bottom: 1px solid rgba(255, 255, 255, 0.1);
display: flex;
align-items: center;
gap: 12px;
}
.logo-icon {
width: 36px;
height: 36px;
background: var(--primary-color);
border-radius: 8px;
display: flex;
align-items: center;
justify-content: center;
color: white;
font-weight: 700;
font-size: 18px;
}
.logo-text {
color: white;
font-size: 16px;
font-weight: 600;
}
.sidebar-menu {
padding: 16px 0;
}
.nav-group-title {
padding: 12px 20px 8px;
font-size: 11px;
font-weight: 600;
color: var(--text-tertiary);
text-transform: uppercase;
letter-spacing: 0.5px;
}
.menu-item, .nav-item {
display: flex;
align-items: center;
gap: 12px;
padding: 12px 20px;
color: var(--text-light);
text-decoration: none;
font-size: 14px;
font-weight: 500;
transition: all 0.2s;
position: relative;
cursor: pointer;
border: none;
background: none;
width: 100%;
text-align: left;
}
.menu-item:hover, .nav-item:hover {
background: rgba(27, 100, 243, 0.15);
color: white;
}
.menu-item.active, .nav-item.active {
background: rgba(27, 100, 243, 0.2);
color: white;
}
.nav-item.active::before {
content: '';
position: absolute;
left: 0;
top: 0;
bottom: 0;
width: 3px;
background: var(--primary-color);
}
.nav-item.has-submenu {
justify-content: space-between;
}
.nav-arrow {
width: 14px;
height: 14px;
transition: transform 0.2s;
margin-left: auto;
}
.nav-item.expanded .nav-arrow {
transform: rotate(90deg);
}
.nav-submenu {
display: none;
background: rgba(0, 0, 0, 0.1);
}
.nav-item.expanded + .nav-submenu {
display: block;
}
.nav-subitem {
display: flex;
align-items: center;
gap: 12px;
padding: 10px 20px 10px 48px;
color: var(--text-light);
text-decoration: none;
font-size: 13px;
font-weight: 500;
transition: all 0.2s;
position: relative;
}
.nav-subitem:hover {
background: rgba(27, 100, 243, 0.15);
color: white;
}
.nav-subitem.active {
background: rgba(27, 100, 243, 0.2);
color: white;
}
.nav-icon {
width: 18px;
height: 18px;
stroke: currentColor;
stroke-width: 2;
fill: none;
stroke-linecap: round;
stroke-linejoin: round;
}
/* 顶部工具栏 */
.header, .top-header {
position: fixed;
top: 0;
left: var(--sidebar-width);
right: 0;
height: var(--header-height);
background: var(--card-bg);
border-bottom: 1px solid var(--border-color);
display: flex;
align-items: center;
justify-content: space-between;
padding: 0 32px;
z-index: 999;
box-shadow: var(--shadow-sm);
}
.header-left {
display: flex;
align-items: center;
gap: 24px;
}
.breadcrumb {
display: flex;
align-items: center;
gap: 8px;
font-size: 14px;
color: var(--text-secondary);
}
.breadcrumb-separator {
color: var(--text-tertiary);
}
.breadcrumb-current {
color: var(--text-primary);
font-weight: 500;
}
.header-right {
display: flex;
align-items: center;
gap: 16px;
}
.header-icon-btn {
position: relative;
width: 36px;
height: 36px;
border-radius: 8px;
border: none;
background: transparent;
cursor: pointer;
display: flex;
align-items: center;
justify-content: center;
color: var(--text-secondary);
transition: all 0.2s;
}
.header-icon-btn:hover {
background: var(--bg-color);
color: var(--primary-color);
}
.notification-badge {
position: absolute;
top: 6px;
right: 6px;
width: 8px;
height: 8px;
background: var(--error-color);
border-radius: 50%;
border: 2px solid var(--card-bg);
}
.lang-switcher {
display: flex;
gap: 6px;
align-items: center;
}
.lang-btn {
padding: 6px 12px;
background: transparent;
border: 1px solid var(--border-color);
border-radius: 6px;
color: var(--text-secondary);
font-size: 13px;
cursor: pointer;
transition: all 0.2s;
}
.lang-btn:hover {
border-color: var(--primary-color);
color: var(--primary-color);
background: rgba(27, 100, 243, 0.05);
}
.lang-btn.active {
background: var(--primary-color);
border-color: var(--primary-color);
color: white;
}
.user-avatar {
width: 36px;
height: 36px;
border-radius: 8px;
background: var(--primary-color);
color: white;
display: flex;
align-items: center;
justify-content: center;
font-weight: 600;
font-size: 14px;
cursor: pointer;
}
.page-title {
font-size: 20px;
font-weight: 600;
color: var(--text-primary);
}
.user-info {
display: flex;
align-items: center;
gap: 16px;
}
.notification {
position: relative;
cursor: pointer;
color: var(--text-secondary);
}
/* 主内容区域 - 已调整左右内边距 */
.main-content {
flex: 1;
padding: 24px;
overflow-y: auto;
min-height: 100vh;
margin-left: 260px;
margin-left: var(--sidebar-width);
margin-top: var(--header-height);
/* 调整左右内边距,从 8px 增加到 32px,以利用更多空间 */
/* padding: 4px 32px;
min-height: calc(100vh - var(--header-height));
.main-content { } */
}
.content-area {
padding: 0;
}
/* 页面标题区域 */
.page-header {
display: flex;
justify-content: space-between;
align-items: center;
margin-bottom: 24px;
}
.page-title-section {
display: flex;
flex-direction: column;
gap: 4px;
}
.page-title-main {
font-size: 24px;
font-weight: 600;
color: var(--text-primary);
letter-spacing: -0.3px;
}
.page-title-sub {
font-size: 14px;
color: var(--text-secondary);
}
/* 表格数据优化 */
.table-cell-number {
font-weight: 600;
color: var(--text-primary);
}
.table-cell-date {
color: var(--text-secondary);
font-size: 13px;
}
/* 表格内容样式增强 */
td strong {
color: var(--text-primary);
font-weight: 600;
}
td code {
font-size: 12px;
font-weight: 500;
}
/* 空状态 */
.empty-state {
text-align: center;
padding: 60px 20px;
color: var(--text-secondary);
}
.empty-state-icon {
font-size: 48px;
color: var(--text-tertiary);
margin-bottom: 16px;
}
.empty-state-text {
font-size: 14px;
color: var(--text-secondary);
}
/* 响应式表格优化 */
@media (max-width: 1200px) {
.table-container {
overflow-x: auto;
}
table {
min-width: 1000px;
}
}
@media (max-width: 768px) {
.card-body {
padding: 16px;
}
th, td {
padding: 12px 16px;
}
.action-buttons {
flex-direction: column;
gap: 6px;
}
.action-btn {
width: 100%;
justify-content: center;
}
}
/* 卡片样式 */
.card {
background: var(--card-bg);
border-radius: 12px;
box-shadow: var(--shadow-sm);
margin-bottom: 24px;
border: 1px solid var(--border-color);
}
.card-header {
padding: 18px 20px;
border-bottom: 1px solid var(--border-color);
display: flex;
align-items: center;
justify-content: space-between;
background: var(--bg-color);
}
.card-title {
font-size: 18px;
font-weight: 600;
color: var(--text-primary);
letter-spacing: -0.2px;
}
.card-body {
padding: 20px 16px;
}
/* 按钮样式 */
.btn {
padding: 10px 20px;
border: none;
border-radius: 8px;
cursor: pointer;
font-size: 14px;
font-weight: 500;
transition: all 0.2s;
display: inline-flex;
align-items: center;
gap: 8px;
}
.btn-primary {
background: var(--primary-color);
color: white;
}
.btn-primary:hover {
background: var(--primary-hover);
transform: translateY(-1px);
box-shadow: 0 4px 12px rgba(27, 100, 243, 0.3);
}
.btn-secondary {
background: #f0f0f0;
color: var(--text-light);
}
.btn-secondary:hover {
background: #e0e0e0;
}
.btn-success {
background: var(--success-color);
color: white;
}
.btn-success:hover {
background: #389e0d;
}
.btn-danger {
background: var(--error-color);
color: white;
}
.btn-danger:hover {
background: #cf1322;
}
/* 标签页样式 */
.tabs {
display: flex;
gap: 16px;
margin-bottom: 20px;
border-bottom: 1px solid var(--border-color);
}
.tab {
padding: 10px 0;
color: var(--text-light);
cursor: pointer;
border-bottom: 2px solid transparent;
transition: all 0.3s ease;
font-size: 14px;
}
.tab:hover {
color: var(--primary-color);
}
.tab.active {
color: var(--primary-color);
border-bottom-color: var(--primary-color);
}
/* 表格样式 */
.table-container {
overflow-x: auto;
border-radius: 8px;
width: 100%;
}
table {
width: 100%;
border-collapse: collapse;
background: var(--card-bg);
}
th, td {
padding: 16px 20px;
text-align: left;
border-bottom: 1px solid var(--border-color);
}
th {
background: var(--bg-color);
font-weight: 600;
color: var(--text-secondary);
font-size: 13px;
text-transform: uppercase;
letter-spacing: 0.5px;
white-space: nowrap;
}
tbody tr {
transition: all 0.2s;
}
tbody tr:hover {
background: rgba(27, 100, 243, 0.04);
}
tbody tr:last-child td {
border-bottom: none;
}
td {
color: var(--text-primary);
font-size: 14px;
vertical-align: middle;
}
.status {
padding: 4px 8px;
border-radius: 4px;
font-size: 12px;
font-weight: 500;
}
.status.active {
background: #f6ffed;
color: var(--success-color);
}
.status.inactive {
background: #fff2e8;
color: var(--warning-color);
}
.action-buttons {
display: flex;
gap: 8px;
flex-wrap: wrap;
}
.action-btn {
padding: 6px 14px;
border: none;
border-radius: 6px;
cursor: pointer;
font-size: 13px;
font-weight: 500;
transition: all 0.2s;
display: inline-flex;
align-items: center;
gap: 6px;
white-space: nowrap;
}
.action-btn i {
font-size: 12px;
}
.action-btn.edit-btn {
background: rgba(27, 100, 243, 0.1);
color: var(--primary-color);
}
.action-btn.edit-btn:hover {
background: rgba(27, 100, 243, 0.2);
transform: translateY(-1px);
box-shadow: 0 2px 8px rgba(27, 100, 243, 0.2);
}
.action-btn.delete-btn {
background: rgba(239, 68, 68, 0.1);
color: var(--error-color);
}
.action-btn.delete-btn:hover {
background: rgba(239, 68, 68, 0.2);
transform: translateY(-1px);
box-shadow: 0 2px 8px rgba(239, 68, 68, 0.2);
}
.action-btn.view-btn {
background: rgba(27, 100, 243, 0.08);
color: var(--primary-color);
}
.action-btn.view-btn:hover {
background: rgba(27, 100, 243, 0.15);
transform: translateY(-1px);
box-shadow: 0 2px 8px rgba(27, 100, 243, 0.2);
}
.action-btn.copy-btn {
background: rgba(34, 197, 94, 0.1);
color: var(--success-color);
}
.action-btn.copy-btn:hover {
background: rgba(34, 197, 94, 0.2);
transform: translateY(-1px);
box-shadow: 0 2px 8px rgba(34, 197, 94, 0.2);
}
/* 模态框样式 */
.modal {
display: none;
position: fixed;
top: 0;
left: 0;
width: 100%;
height: 100%;
background: rgba(0, 0, 0, 0.5);
z-index: 2000;
align-items: center;
justify-content: center;
}
.modal.show {
display: flex;
}
.modal-content {
background: white;
border-radius: 8px;
box-shadow: 0 4px 16px rgba(0, 0, 0, 0.15);
width: 90%;
max-width: 600px;
max-height: 80vh;
overflow-y: auto;
}
.add-modal-content {
background: white;
border-radius: 8px;
box-shadow: 0 4px 16px rgba(0, 0, 0, 0.15);
width: 90%;
max-width: 800px;
max-height: 85vh;
overflow-y: auto;
}
.modal-header {
padding: 16px 24px;
border-bottom: 1px solid var(--border-color);
display: flex;
align-items: center;
justify-content: space-between;
}
.modal-title {
font-size: 16px;
font-weight: 600;
color: var(--text-color);
}
.close-modal {
background: none;
border: none;
font-size: 20px;
color: var(--text-light);
cursor: pointer;
padding: 0;
width: 30px;
height: 30px;
display: flex;
align-items: center;
justify-content: center;
border-radius: 4px;
transition: all 0.3s;
}
.close-modal:hover {
background: var(--secondary-color);
color: var(--text-color);
}
.modal-body {
padding: 24px;
}
.modal-footer {
padding: 16px 24px;
border-top: 1px solid var(--border-color);
display: flex;
align-items: center;
justify-content: flex-end;
gap: 12px;
}
/* 新增表单模态框样式 */
.add-modal-form .form-group {
margin-bottom: 20px;
}
.add-modal-form .form-row {
display: flex;
gap: 15px;
margin-bottom: 15px;
}
.add-modal-form .form-row .form-group {
flex: 1;
margin-bottom: 0;
}
.add-modal-form label {
display: block;
margin-bottom: 6px;
font-weight: 500;
color: var(--text-secondary);
font-size: 14px;
}
.add-modal-form input,
.add-modal-form select,
.add-modal-form textarea {
width: 100%;
padding: 8px 12px;
border: 1px solid var(--border-color);
border-radius: 6px;
font-size: 14px;
transition: border-color 0.3s;
}
.add-modal-form input:focus,
.add-modal-form select:focus,
.add-modal-form textarea:focus {
outline: none;
border-color: var(--primary-color);
}
.add-modal-form .section-title {
font-size: 16px;
font-weight: 600;
color: var(--text-primary);
margin: 20px 0 15px 0;
padding-bottom: 8px;
border-bottom: 1px solid var(--border-color);
}
.upload-box {
border: 2px dashed var(--border-color);
border-radius: 8px;
padding: 20px;
text-align: center;
cursor: pointer;
transition: all 0.3s;
background-color: var(--bg-color);
}
.upload-box:hover {
border-color: var(--primary-color);
background-color: rgba(27, 100, 243, 0.05);
}
.upload-icon {
font-size: 24px;
color: var(--primary-color);
margin-bottom: 10px;
}
.upload-info {
color: var(--text-secondary);
font-size: 13px;
}
.file-name {
margin-top: 10px;
font-weight: 500;
color: var(--primary-color);
font-size: 13px;
}
.param-table {
width: 100%;
border-collapse: collapse;
margin-top: 10px;
}
.param-table th, .param-table td {
border: 1px solid var(--border-color);
padding: 8px;
text-align: left;
}
.param-table th {
background-color: var(--bg-color);
font-weight: 600;
}
.add-param-btn {
background: var(--primary-color);
color: white;
border: none;
padding: 8px 15px;
border-radius: 6px;
cursor: pointer;
margin-top: 10px;
font-size: 14px;
}
.add-param-btn:hover {
background: var(--primary-hover);
}
/* 二维码预览样式 */
.qrcode-preview-large {
display: flex;
flex-direction: column;
align-items: center;
padding: 20px;
background: var(--primary-light);
border-radius: 8px;
margin-bottom: 20px;
}
.qrcode-image {
width: 200px;
height: 200px;
background: white;
padding: 10px;
border-radius: 8px;
box-shadow: 0 2px 8px rgba(0, 0, 0, 0.1);
display: flex;
align-items: center;
justify-content: center;
margin-bottom: 15px;
}
.qrcode-image img {
max-width: 100%;
max-height: 100%;
}
/* 详情信息样式 */
.detail-info {
margin-top: 20px;
}
.detail-item {
display: flex;
margin-bottom: 12px;
font-size: 14px;
}
.detail-label {
width: 100px;
color: var(--text-light);
flex-shrink: 0;
}
.detail-value {
color: var(--text-color);
font-weight: 500;
}
/* 响应式设计 */
@media (max-width: 768px) {
.sidebar {
transform: translateX(-100%);
}
.sidebar.show-mobile {
transform: translateX(0);
}
.main-content {
margin-left: 0;
margin-top: 0;
padding: 16px; /* 在移动端保持较小的内边距 */
}
.header, .top-header {
left: 0;
}
.tabs {
flex-wrap: wrap;
}
}
/* 批量上传相关样式 */
.batch-upload-modal .modal-content {
max-width: 800px;
}
.template-selector {
margin-bottom: 20px;
}
.template-selector label {
display: block;
margin-bottom: 8px;
font-weight: 500;
color: var(--text-primary);
}
.template-selector select {
width: 100%;
padding: 10px 15px;
border: 1px solid var(--border-color);
border-radius: 6px;
font-size: 14px;
background: white;
}
.template-download-btn {
margin-top: 10px;
padding: 8px 16px;
background: var(--primary-color);
color: white;
border: none;
border-radius: 6px;
cursor: pointer;
font-size: 14px;
display: inline-flex;
align-items: center;
gap: 6px;
}
.template-download-btn:hover {
background: var(--primary-hover);
}
.upload-area {
border: 2px dashed var(--border-color);
border-radius: 8px;
padding: 40px 20px;
text-align: center;
margin-bottom: 20px;
cursor: pointer;
transition: all 0.3s;
background: var(--bg-color);
}
.upload-area:hover {
border-color: var(--primary-color);
background: rgba(27, 100, 243, 0.05);
}
.upload-area.dragover {
border-color: var(--primary-color);
background: rgba(27, 100, 243, 0.1);
}
.upload-icon-large {
font-size: 48px;
color: var(--primary-color);
margin-bottom: 12px;
}
.upload-text {
font-size: 14px;
color: var(--text-secondary);
margin-bottom: 8px;
}
.upload-hint {
font-size: 12px;
color: var(--text-tertiary);
}
.progress-section {
margin-top: 20px;
padding-top: 20px;
border-top: 1px solid var(--border-color);
}
.progress-info {
display: flex;
justify-content: space-between;
align-items: center;
margin-bottom: 12px;
font-size: 14px;
}
.progress-stats {
display: flex;
gap: 20px;
}
.stat-item {
display: flex;
align-items: center;
gap: 6px;
}
.stat-label {
color: var(--text-secondary);
}
.stat-value {
font-weight: 600;
color: var(--text-primary);
}
.stat-value.success {
color: var(--success-color);
}
.stat-value.error {
color: var(--error-color);
}
.progress-bar-container {
width: 100%;
height: 8px;
background: var(--bg-color);
border-radius: 4px;
overflow: hidden;
margin-bottom: 12px;
}
.progress-bar {
height: 100%;
background: var(--primary-color);
transition: width 0.3s ease;
border-radius: 4px;
}
.error-list {
margin-top: 16px;
max-height: 200px;
overflow-y: auto;
border: 1px solid var(--border-color);
border-radius: 6px;
padding: 12px;
background: #fff5f5;
}
.error-item {
padding: 8px;
margin-bottom: 6px;
background: white;
border-left: 3px solid var(--error-color);
border-radius: 4px;
font-size: 13px;
}
.error-item:last-child {
margin-bottom: 0;
}
.error-row {
display: flex;
justify-content: space-between;
align-items: center;
}
.error-reason {
color: var(--error-color);
font-weight: 500;
}
.download-error-btn {
margin-top: 12px;
padding: 8px 16px;
background: var(--error-color);
color: white;
border: none;
border-radius: 6px;
cursor: pointer;
font-size: 13px;
display: inline-flex;
align-items: center;
gap: 6px;
}
.download-error-btn:hover {
background: #cf1322;
}
.validation-table {
width: 100%;
border-collapse: collapse;
margin-top: 16px;
font-size: 13px;
table-layout: fixed;
}
.validation-table th,
.validation-table td {
padding: 10px;
text-align: left;
border-bottom: 1px solid var(--border-color);
white-space: normal;
word-break: normal;
overflow: visible;
vertical-align: middle;
}
.validation-table th {
background: var(--bg-color);
font-weight: 600;
color: var(--text-secondary);
white-space: nowrap;
}
.validation-table td {
white-space: nowrap;
overflow: hidden;
text-overflow: ellipsis;
}
.validation-table td:nth-child(5) {
white-space: normal;
word-break: break-word;
}
.validation-table th:nth-child(1),
.validation-table td:nth-child(1) {
width: 60px;
min-width: 60px;
text-align: center;
}
.validation-table th:nth-child(2),
.validation-table td:nth-child(2) {
width: 120px;
min-width: 120px;
}
.validation-table th:nth-child(3),
.validation-table td:nth-child(3) {
width: 120px;
min-width: 120px;
}
.validation-table th:nth-child(4),
.validation-table td:nth-child(4) {
width: 100px;
min-width: 100px;
text-align: center;
}
.validation-table th:nth-child(5),
.validation-table td:nth-child(5) {
width: auto;
min-width: 200px;
}
.validation-table tr.error-row {
background: #fff5f5;
}
.validation-table tr.error-row td {
color: var(--error-color);
}
#validation-table-container {
overflow-x: auto;
max-width: 100%;
width: 100%;
}
#validation-table-container table {
min-width: 600px;
}
.file-name-display {
margin-top: 12px;
padding: 10px;
background: var(--bg-color);
border-radius: 6px;
font-size: 13px;
color: var(--text-secondary);
}
table {
width: 100%;
border-collapse: collapse;
}
th {
background-color: #01337a;
color: #fff;
padding: 10px;
text-align: left;
border: 1px solid #ddd;
}
td {
padding: 10px;
border: 1px solid #ddd;
}
tr:nth-child(even) {
background-color: #f2f2f2;
}
/* 在主页面CSS中添加 */
.sidebar-iframe {
position: fixed;
left: 0;
top: 0;
width: var(--sidebar-width);
height: 100vh;
border: none;
z-index: 999;
}
/* 为main-content和header添加左边距以避开iframe */
.main-content {
margin-left: var(--sidebar-width);
margin-top: var(--header-height);
}
.top-header {
left: var(--sidebar-width);
}
</style>
</head>
<body>
<div class="app-container">
<div id="sidebar-container"></div>
<header class="top-header">
<div class="header-left">
<div class="breadcrumb">
<span>首页</span>
<span class="breadcrumb-separator">/</span>
<span class="breadcrumb-current">配件管理</span>
</div>
</div>
<div class="header-right">
<button class="header-icon-btn" title="通知">
<svg class="nav-icon" viewBox="0 0 20 20">
<path d="M10 2a6 6 0 00-6 6v3.586l-.707.707A1 1 0 004 14h12a1 1 0 00.707-1.707L16 11.586V8a6 6 0 00-6-6zM10 18a3 3 0 01-3-3h6a3 3 0 01-3 3z"/>
</svg>
<span class="notification-badge"></span>
</button>
<div class="lang-switcher">
<button class="lang-btn active">中文</button>
<button class="lang-btn">EN</button>
</div>
<div class="user-avatar"></div>
</div>
</header>
<div class="main-content" style="position: relative;">
<!-- <img src="./image/img_1.png" alt="" style="width: 100%;display:block;">-->
<div id="app">
<div class="container">
<div class="card" style="padding: 20px;">
<!-- <div class="toolbar">
<div class="card-title">零件费用标准列表</div>
<div style="display: flex; gap: 10px;">
<button class="btn btn-success" @click="handleImport">批量导入</button>
<button class="btn btn-primary" @click="handleAdd">+ 新增零件</button>
</div>
</div>-->
<div class="page-header">
<div>
<h1 class="page-title" data-i18n="title">配件管理</h1>
</div>
<div class="toolbar" style="display:flex;justify-content: end;margin-bottom: 20px;">
<button class="btn btn-primary" style="text-align: right;padding: 8px 28px;margin-right: 4px;" @click="handleAdd">批量导入</button>
<button class="btn btn-primary" style="text-align: right;padding: 8px 28px;" @click="handleAdd">+ 新增配件</button>
</div>
</div>
<table class="data-table">
<thead>
<tr>
<th>零件编号</th>
<th>零件名称</th>
<th>型号规格</th>
<!-- <th>标准单价</th>-->
<th>单位</th>
<th>适用设备</th>
<th>寿命周期</th>
<th>保养周期</th>
<th>状态</th>
<th>操作</th>
</tr>
</thead>
<tbody>
<tr v-for="item in partList" :key="item.id">
<td>{{ item.partNo }}</td>
<td>{{ item.partName }}</td>
<td>{{ item.specification }}</td>
<!-- <td>¥{{ item.price }}</td>-->
<td>{{ item.unit }}</td>
<td>{{ item.applicableEquipment }}</td>
<td>{{ item.lifecycle }} 月</td>
<td>{{ item.maintenanceCycle }} 天</td>
<td>
<span :class="item.status === '启用' ? 'badge badge-success' : 'badge badge-danger'">
{{ item.status }}
</span>
</td>
<td>
<div class="action-btns">
<button class="btn btn-primary btn-small" style="padding: 4px 14px" @click="handleEdit(item)">编辑</button>
</div>
</td>
</tr>
</tbody>
</table>
</div>
</div>
</div>
<script>
const { createApp } = Vue;
createApp({
data() {
return {
partList: [
{
id: 1,
partNo: 'P001',
partName: '服务器硬盘',
specification: '2TB SATA',
price: 800,
unit: '块',
applicableEquipment: '服务器',
lifecycle: 60,
maintenanceCycle: 30,
status: '启用'
},
{
id: 2,
partNo: 'P002',
partName: '内存条',
specification: '16GB DDR4',
price: 600,
unit: '条',
applicableEquipment: '服务器/工作站',
lifecycle: 36,
maintenanceCycle: 90,
status: '启用'
},
{
id: 3,
partNo: 'P003',
partName: '网络交换机',
specification: '24口千兆',
price: 2000,
unit: '台',
applicableEquipment: '网络设备',
lifecycle: 120,
maintenanceCycle: 180,
status: '启用'
},
{
id: 4,
partNo: 'P004',
partName: 'UPS电源',
specification: '3KVA',
price: 3500,
unit: '台',
applicableEquipment: '电源设备',
lifecycle: 120,
maintenanceCycle: 30,
status: '启用'
}
]
}
},
methods: {
handleAdd() {
window.location.href = '配件编辑新增.html?action=add';
},
handleEdit(item) {
window.location.href = `配件编辑新增.html?action=edit&id=${item.id}`;
},
handleImport() {
alert('批量导入功能(占位)');
}
}
}).mount('#app');
</script>
</div>
</div>
</body>
<script src="./js.js"></script>
</html>
\ No newline at end of file
<!DOCTYPE html>
<!DOCTYPE html>
<html lang="zh-CN">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>设备档案</title>
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/6.4.0/css/all.min.css">
<style>
:root {
--primary-color: #1B64F3;
--primary-hover: #1554D3;
--primary-light: #e6f7ff;
--bg-color: #F5F6FA;
--card-bg: #FFFFFF;
--sidebar-bg: #0F172A;
--text-primary: #1A1F36;
--text-secondary: #64748B;
--text-tertiary: #94A3B8;
--text-light: #CBD5E1;
--border-color: #E2E8F0;
--shadow-sm: 0 2px 8px rgba(0, 0, 0, 0.06);
--shadow-md: 0 4px 12px rgba(0, 0, 0, 0.08);
--success-color: #22C55E;
--warning-color: #EAB308;
--error-color: #EF4444;
--sidebar-width: 260px;
--header-height: 64px;
}
* {
margin: 0;
padding: 0;
box-sizing: border-box;
font-family: "PingFang SC", "Microsoft YaHei", sans-serif;
}
body {
font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', 'Roboto', 'Helvetica Neue', Arial, 'PingFang SC', 'Microsoft YaHei', sans-serif;
background-color: var(--bg-color);
color: var(--text-primary);
line-height: 1.6;
overflow-x: hidden;
}
.app-container {
display: flex;
min-height: 100vh;
}
/* 左侧导航栏 */
.sidebar {
position: fixed;
left: 0;
top: 0;
width: var(--sidebar-width);
height: 100vh;
background: var(--sidebar-bg);
border-right: 1px solid rgba(255, 255, 255, 0.1);
overflow-y: auto;
z-index: 1000;
}
.sidebar-logo {
padding: 20px;
border-bottom: 1px solid rgba(255, 255, 255, 0.1);
display: flex;
align-items: center;
gap: 12px;
}
.logo-icon {
width: 36px;
height: 36px;
background: var(--primary-color);
border-radius: 8px;
display: flex;
align-items: center;
justify-content: center;
color: white;
font-weight: 700;
font-size: 18px;
}
.logo-text {
color: white;
font-size: 16px;
font-weight: 600;
}
.sidebar-menu {
padding: 16px 0;
}
.nav-group-title {
padding: 12px 20px 8px;
font-size: 11px;
font-weight: 600;
color: var(--text-tertiary);
text-transform: uppercase;
letter-spacing: 0.5px;
}
.menu-item, .nav-item {
display: flex;
align-items: center;
gap: 12px;
padding: 12px 20px;
color: var(--text-light);
text-decoration: none;
font-size: 14px;
font-weight: 500;
transition: all 0.2s;
position: relative;
cursor: pointer;
border: none;
background: none;
width: 100%;
text-align: left;
}
.menu-item:hover, .nav-item:hover {
background: rgba(27, 100, 243, 0.15);
color: white;
}
.menu-item.active, .nav-item.active {
background: rgba(27, 100, 243, 0.2);
color: white;
}
.nav-item.active::before {
content: '';
position: absolute;
left: 0;
top: 0;
bottom: 0;
width: 3px;
background: var(--primary-color);
}
.nav-item.has-submenu {
justify-content: space-between;
}
.nav-arrow {
width: 14px;
height: 14px;
transition: transform 0.2s;
margin-left: auto;
}
.nav-item.expanded .nav-arrow {
transform: rotate(90deg);
}
.nav-submenu {
display: none;
background: rgba(0, 0, 0, 0.1);
}
.nav-item.expanded + .nav-submenu {
display: block;
}
.nav-subitem {
display: flex;
align-items: center;
gap: 12px;
padding: 10px 20px 10px 48px;
color: var(--text-light);
text-decoration: none;
font-size: 13px;
font-weight: 500;
transition: all 0.2s;
position: relative;
}
.nav-subitem:hover {
background: rgba(27, 100, 243, 0.15);
color: white;
}
.nav-subitem.active {
background: rgba(27, 100, 243, 0.2);
color: white;
}
.nav-icon {
width: 18px;
height: 18px;
stroke: currentColor;
stroke-width: 2;
fill: none;
stroke-linecap: round;
stroke-linejoin: round;
}
/* 顶部工具栏 */
.header, .top-header {
position: fixed;
top: 0;
left: var(--sidebar-width);
right: 0;
height: var(--header-height);
background: var(--card-bg);
border-bottom: 1px solid var(--border-color);
display: flex;
align-items: center;
justify-content: space-between;
padding: 0 32px;
z-index: 999;
box-shadow: var(--shadow-sm);
}
.header-left {
display: flex;
align-items: center;
gap: 24px;
}
.breadcrumb {
display: flex;
align-items: center;
gap: 8px;
font-size: 14px;
color: var(--text-secondary);
}
.breadcrumb-separator {
color: var(--text-tertiary);
}
.breadcrumb-current {
color: var(--text-primary);
font-weight: 500;
}
.header-right {
display: flex;
align-items: center;
gap: 16px;
}
.header-icon-btn {
position: relative;
width: 36px;
height: 36px;
border-radius: 8px;
border: none;
background: transparent;
cursor: pointer;
display: flex;
align-items: center;
justify-content: center;
color: var(--text-secondary);
transition: all 0.2s;
}
.header-icon-btn:hover {
background: var(--bg-color);
color: var(--primary-color);
}
.notification-badge {
position: absolute;
top: 6px;
right: 6px;
width: 8px;
height: 8px;
background: var(--error-color);
border-radius: 50%;
border: 2px solid var(--card-bg);
}
.lang-switcher {
display: flex;
gap: 6px;
align-items: center;
}
.lang-btn {
padding: 6px 12px;
background: transparent;
border: 1px solid var(--border-color);
border-radius: 6px;
color: var(--text-secondary);
font-size: 13px;
cursor: pointer;
transition: all 0.2s;
}
.lang-btn:hover {
border-color: var(--primary-color);
color: var(--primary-color);
background: rgba(27, 100, 243, 0.05);
}
.lang-btn.active {
background: var(--primary-color);
border-color: var(--primary-color);
color: white;
}
.user-avatar {
width: 36px;
height: 36px;
border-radius: 8px;
background: var(--primary-color);
color: white;
display: flex;
align-items: center;
justify-content: center;
font-weight: 600;
font-size: 14px;
cursor: pointer;
}
.page-title {
font-size: 20px;
font-weight: 600;
color: var(--text-primary);
}
.user-info {
display: flex;
align-items: center;
gap: 16px;
}
.notification {
position: relative;
cursor: pointer;
color: var(--text-secondary);
}
/* 主内容区域 - 已调整左右内边距 */
.main-content {
flex: 1;
padding: 24px;
overflow-y: auto;
min-height: 100vh;
margin-left: 260px;
margin-left: var(--sidebar-width);
margin-top: var(--header-height);
/* 调整左右内边距,从 8px 增加到 32px,以利用更多空间 */
/* padding: 4px 32px;
min-height: calc(100vh - var(--header-height));
.main-content { } */
}
.content-area {
padding: 0;
}
/* 页面标题区域 */
.page-header {
display: flex;
justify-content: space-between;
align-items: center;
margin-bottom: 24px;
}
.page-title-section {
display: flex;
flex-direction: column;
gap: 4px;
}
.page-title-main {
font-size: 24px;
font-weight: 600;
color: var(--text-primary);
letter-spacing: -0.3px;
}
.page-title-sub {
font-size: 14px;
color: var(--text-secondary);
}
/* 表格数据优化 */
.table-cell-number {
font-weight: 600;
color: var(--text-primary);
}
.table-cell-date {
color: var(--text-secondary);
font-size: 13px;
}
/* 表格内容样式增强 */
td strong {
color: var(--text-primary);
font-weight: 600;
}
td code {
font-size: 12px;
font-weight: 500;
}
/* 空状态 */
.empty-state {
text-align: center;
padding: 60px 20px;
color: var(--text-secondary);
}
.empty-state-icon {
font-size: 48px;
color: var(--text-tertiary);
margin-bottom: 16px;
}
.empty-state-text {
font-size: 14px;
color: var(--text-secondary);
}
/* 响应式表格优化 */
@media (max-width: 1200px) {
.table-container {
overflow-x: auto;
}
table {
min-width: 1000px;
}
}
@media (max-width: 768px) {
.card-body {
padding: 16px;
}
th, td {
padding: 12px 16px;
}
.action-buttons {
flex-direction: column;
gap: 6px;
}
.action-btn {
width: 100%;
justify-content: center;
}
}
/* 卡片样式 */
.card {
background: var(--card-bg);
border-radius: 12px;
box-shadow: var(--shadow-sm);
margin-bottom: 24px;
border: 1px solid var(--border-color);
}
.card-header {
padding: 18px 20px;
border-bottom: 1px solid var(--border-color);
display: flex;
align-items: center;
justify-content: space-between;
background: var(--bg-color);
}
.card-title {
font-size: 18px;
font-weight: 600;
color: var(--text-primary);
letter-spacing: -0.2px;
}
.card-body {
padding: 20px 16px;
}
/* 按钮样式 */
.btn {
padding: 10px 20px;
border: none;
border-radius: 8px;
cursor: pointer;
font-size: 14px;
font-weight: 500;
transition: all 0.2s;
display: inline-flex;
align-items: center;
gap: 8px;
}
.btn-primary {
background: var(--primary-color);
color: white;
}
.btn-primary:hover {
background: var(--primary-hover);
transform: translateY(-1px);
box-shadow: 0 4px 12px rgba(27, 100, 243, 0.3);
}
.btn-secondary {
background: #f0f0f0;
color: var(--text-light);
}
.btn-secondary:hover {
background: #e0e0e0;
}
.btn-success {
background: var(--success-color);
color: white;
}
.btn-success:hover {
background: #389e0d;
}
.btn-danger {
background: var(--error-color);
color: white;
}
.btn-danger:hover {
background: #cf1322;
}
/* 标签页样式 */
.tabs {
display: flex;
gap: 16px;
margin-bottom: 20px;
border-bottom: 1px solid var(--border-color);
}
.tab {
padding: 10px 0;
color: var(--text-light);
cursor: pointer;
border-bottom: 2px solid transparent;
transition: all 0.3s ease;
font-size: 14px;
}
.tab:hover {
color: var(--primary-color);
}
.tab.active {
color: var(--primary-color);
border-bottom-color: var(--primary-color);
}
/* 表格样式 */
.table-container {
overflow-x: auto;
border-radius: 8px;
width: 100%;
}
table {
width: 100%;
border-collapse: collapse;
background: var(--card-bg);
}
th, td {
padding: 16px 20px;
text-align: left;
border-bottom: 1px solid var(--border-color);
}
th {
background: var(--bg-color);
font-weight: 600;
color: var(--text-secondary);
font-size: 13px;
text-transform: uppercase;
letter-spacing: 0.5px;
white-space: nowrap;
}
tbody tr {
transition: all 0.2s;
}
tbody tr:hover {
background: rgba(27, 100, 243, 0.04);
}
tbody tr:last-child td {
border-bottom: none;
}
td {
color: var(--text-primary);
font-size: 14px;
vertical-align: middle;
}
.status {
padding: 4px 8px;
border-radius: 4px;
font-size: 12px;
font-weight: 500;
}
.status.active {
background: #f6ffed;
color: var(--success-color);
}
.status.inactive {
background: #fff2e8;
color: var(--warning-color);
}
.action-buttons {
display: flex;
gap: 8px;
flex-wrap: wrap;
}
.action-btn {
padding: 6px 14px;
border: none;
border-radius: 6px;
cursor: pointer;
font-size: 13px;
font-weight: 500;
transition: all 0.2s;
display: inline-flex;
align-items: center;
gap: 6px;
white-space: nowrap;
}
.action-btn i {
font-size: 12px;
}
.action-btn.edit-btn {
background: rgba(27, 100, 243, 0.1);
color: var(--primary-color);
}
.action-btn.edit-btn:hover {
background: rgba(27, 100, 243, 0.2);
transform: translateY(-1px);
box-shadow: 0 2px 8px rgba(27, 100, 243, 0.2);
}
.action-btn.delete-btn {
background: rgba(239, 68, 68, 0.1);
color: var(--error-color);
}
.action-btn.delete-btn:hover {
background: rgba(239, 68, 68, 0.2);
transform: translateY(-1px);
box-shadow: 0 2px 8px rgba(239, 68, 68, 0.2);
}
.action-btn.view-btn {
background: rgba(27, 100, 243, 0.08);
color: var(--primary-color);
}
.action-btn.view-btn:hover {
background: rgba(27, 100, 243, 0.15);
transform: translateY(-1px);
box-shadow: 0 2px 8px rgba(27, 100, 243, 0.2);
}
.action-btn.copy-btn {
background: rgba(34, 197, 94, 0.1);
color: var(--success-color);
}
.action-btn.copy-btn:hover {
background: rgba(34, 197, 94, 0.2);
transform: translateY(-1px);
box-shadow: 0 2px 8px rgba(34, 197, 94, 0.2);
}
/* 模态框样式 */
.modal {
display: none;
position: fixed;
top: 0;
left: 0;
width: 100%;
height: 100%;
background: rgba(0, 0, 0, 0.5);
z-index: 2000;
align-items: center;
justify-content: center;
}
.modal.show {
display: flex;
}
.modal-content {
background: white;
border-radius: 8px;
box-shadow: 0 4px 16px rgba(0, 0, 0, 0.15);
width: 90%;
max-width: 600px;
max-height: 80vh;
overflow-y: auto;
}
.add-modal-content {
background: white;
border-radius: 8px;
box-shadow: 0 4px 16px rgba(0, 0, 0, 0.15);
width: 90%;
max-width: 800px;
max-height: 85vh;
overflow-y: auto;
}
.modal-header {
padding: 16px 24px;
border-bottom: 1px solid var(--border-color);
display: flex;
align-items: center;
justify-content: space-between;
}
.modal-title {
font-size: 16px;
font-weight: 600;
color: var(--text-color);
}
.close-modal {
background: none;
border: none;
font-size: 20px;
color: var(--text-light);
cursor: pointer;
padding: 0;
width: 30px;
height: 30px;
display: flex;
align-items: center;
justify-content: center;
border-radius: 4px;
transition: all 0.3s;
}
.close-modal:hover {
background: var(--secondary-color);
color: var(--text-color);
}
.modal-body {
padding: 24px;
}
.modal-footer {
padding: 16px 24px;
border-top: 1px solid var(--border-color);
display: flex;
align-items: center;
justify-content: flex-end;
gap: 12px;
}
/* 新增表单模态框样式 */
.add-modal-form .form-group {
margin-bottom: 20px;
}
.add-modal-form .form-row {
display: flex;
gap: 15px;
margin-bottom: 15px;
}
.add-modal-form .form-row .form-group {
flex: 1;
margin-bottom: 0;
}
.add-modal-form label {
display: block;
margin-bottom: 6px;
font-weight: 500;
color: var(--text-secondary);
font-size: 14px;
}
.add-modal-form input,
.add-modal-form select,
.add-modal-form textarea {
width: 100%;
padding: 8px 12px;
border: 1px solid var(--border-color);
border-radius: 6px;
font-size: 14px;
transition: border-color 0.3s;
}
.add-modal-form input:focus,
.add-modal-form select:focus,
.add-modal-form textarea:focus {
outline: none;
border-color: var(--primary-color);
}
.add-modal-form .section-title {
font-size: 16px;
font-weight: 600;
color: var(--text-primary);
margin: 20px 0 15px 0;
padding-bottom: 8px;
border-bottom: 1px solid var(--border-color);
}
.upload-box {
border: 2px dashed var(--border-color);
border-radius: 8px;
padding: 20px;
text-align: center;
cursor: pointer;
transition: all 0.3s;
background-color: var(--bg-color);
}
.upload-box:hover {
border-color: var(--primary-color);
background-color: rgba(27, 100, 243, 0.05);
}
.upload-icon {
font-size: 24px;
color: var(--primary-color);
margin-bottom: 10px;
}
.upload-info {
color: var(--text-secondary);
font-size: 13px;
}
.file-name {
margin-top: 10px;
font-weight: 500;
color: var(--primary-color);
font-size: 13px;
}
.param-table {
width: 100%;
border-collapse: collapse;
margin-top: 10px;
}
.param-table th, .param-table td {
border: 1px solid var(--border-color);
padding: 8px;
text-align: left;
}
.param-table th {
background-color: var(--bg-color);
font-weight: 600;
}
.add-param-btn {
background: var(--primary-color);
color: white;
border: none;
padding: 8px 15px;
border-radius: 6px;
cursor: pointer;
margin-top: 10px;
font-size: 14px;
}
.add-param-btn:hover {
background: var(--primary-hover);
}
/* 二维码预览样式 */
.qrcode-preview-large {
display: flex;
flex-direction: column;
align-items: center;
padding: 20px;
background: var(--primary-light);
border-radius: 8px;
margin-bottom: 20px;
}
.qrcode-image {
width: 200px;
height: 200px;
background: white;
padding: 10px;
border-radius: 8px;
box-shadow: 0 2px 8px rgba(0, 0, 0, 0.1);
display: flex;
align-items: center;
justify-content: center;
margin-bottom: 15px;
}
.qrcode-image img {
max-width: 100%;
max-height: 100%;
}
/* 详情信息样式 */
.detail-info {
margin-top: 20px;
}
.detail-item {
display: flex;
margin-bottom: 12px;
font-size: 14px;
}
.detail-label {
width: 100px;
color: var(--text-light);
flex-shrink: 0;
}
.detail-value {
color: var(--text-color);
font-weight: 500;
}
/* 响应式设计 */
@media (max-width: 768px) {
.sidebar {
transform: translateX(-100%);
}
.sidebar.show-mobile {
transform: translateX(0);
}
.main-content {
margin-left: 0;
margin-top: 0;
padding: 16px; /* 在移动端保持较小的内边距 */
}
.header, .top-header {
left: 0;
}
.tabs {
flex-wrap: wrap;
}
}
/* 批量上传相关样式 */
.batch-upload-modal .modal-content {
max-width: 800px;
}
.template-selector {
margin-bottom: 20px;
}
.template-selector label {
display: block;
margin-bottom: 8px;
font-weight: 500;
color: var(--text-primary);
}
.template-selector select {
width: 100%;
padding: 10px 15px;
border: 1px solid var(--border-color);
border-radius: 6px;
font-size: 14px;
background: white;
}
.template-download-btn {
margin-top: 10px;
padding: 8px 16px;
background: var(--primary-color);
color: white;
border: none;
border-radius: 6px;
cursor: pointer;
font-size: 14px;
display: inline-flex;
align-items: center;
gap: 6px;
}
.template-download-btn:hover {
background: var(--primary-hover);
}
.upload-area {
border: 2px dashed var(--border-color);
border-radius: 8px;
padding: 40px 20px;
text-align: center;
margin-bottom: 20px;
cursor: pointer;
transition: all 0.3s;
background: var(--bg-color);
}
.upload-area:hover {
border-color: var(--primary-color);
background: rgba(27, 100, 243, 0.05);
}
.upload-area.dragover {
border-color: var(--primary-color);
background: rgba(27, 100, 243, 0.1);
}
.upload-icon-large {
font-size: 48px;
color: var(--primary-color);
margin-bottom: 12px;
}
.upload-text {
font-size: 14px;
color: var(--text-secondary);
margin-bottom: 8px;
}
.upload-hint {
font-size: 12px;
color: var(--text-tertiary);
}
.progress-section {
margin-top: 20px;
padding-top: 20px;
border-top: 1px solid var(--border-color);
}
.progress-info {
display: flex;
justify-content: space-between;
align-items: center;
margin-bottom: 12px;
font-size: 14px;
}
.progress-stats {
display: flex;
gap: 20px;
}
.stat-item {
display: flex;
align-items: center;
gap: 6px;
}
.stat-label {
color: var(--text-secondary);
}
.stat-value {
font-weight: 600;
color: var(--text-primary);
}
.stat-value.success {
color: var(--success-color);
}
.stat-value.error {
color: var(--error-color);
}
.progress-bar-container {
width: 100%;
height: 8px;
background: var(--bg-color);
border-radius: 4px;
overflow: hidden;
margin-bottom: 12px;
}
.progress-bar {
height: 100%;
background: var(--primary-color);
transition: width 0.3s ease;
border-radius: 4px;
}
.error-list {
margin-top: 16px;
max-height: 200px;
overflow-y: auto;
border: 1px solid var(--border-color);
border-radius: 6px;
padding: 12px;
background: #fff5f5;
}
.error-item {
padding: 8px;
margin-bottom: 6px;
background: white;
border-left: 3px solid var(--error-color);
border-radius: 4px;
font-size: 13px;
}
.error-item:last-child {
margin-bottom: 0;
}
.error-row {
display: flex;
justify-content: space-between;
align-items: center;
}
.error-reason {
color: var(--error-color);
font-weight: 500;
}
.download-error-btn {
margin-top: 12px;
padding: 8px 16px;
background: var(--error-color);
color: white;
border: none;
border-radius: 6px;
cursor: pointer;
font-size: 13px;
display: inline-flex;
align-items: center;
gap: 6px;
}
.download-error-btn:hover {
background: #cf1322;
}
.validation-table {
width: 100%;
border-collapse: collapse;
margin-top: 16px;
font-size: 13px;
table-layout: fixed;
}
.validation-table th,
.validation-table td {
padding: 10px;
text-align: left;
border-bottom: 1px solid var(--border-color);
white-space: normal;
word-break: normal;
overflow: visible;
vertical-align: middle;
}
.validation-table th {
background: var(--bg-color);
font-weight: 600;
color: var(--text-secondary);
white-space: nowrap;
}
.validation-table td {
white-space: nowrap;
overflow: hidden;
text-overflow: ellipsis;
}
.validation-table td:nth-child(5) {
white-space: normal;
word-break: break-word;
}
.validation-table th:nth-child(1),
.validation-table td:nth-child(1) {
width: 60px;
min-width: 60px;
text-align: center;
}
.validation-table th:nth-child(2),
.validation-table td:nth-child(2) {
width: 120px;
min-width: 120px;
}
.validation-table th:nth-child(3),
.validation-table td:nth-child(3) {
width: 120px;
min-width: 120px;
}
.validation-table th:nth-child(4),
.validation-table td:nth-child(4) {
width: 100px;
min-width: 100px;
text-align: center;
}
.validation-table th:nth-child(5),
.validation-table td:nth-child(5) {
width: auto;
min-width: 200px;
}
.validation-table tr.error-row {
background: #fff5f5;
}
.validation-table tr.error-row td {
color: var(--error-color);
}
#validation-table-container {
overflow-x: auto;
max-width: 100%;
width: 100%;
}
#validation-table-container table {
min-width: 600px;
}
.file-name-display {
margin-top: 12px;
padding: 10px;
background: var(--bg-color);
border-radius: 6px;
font-size: 13px;
color: var(--text-secondary);
}
table {
width: 100%;
border-collapse: collapse;
}
th {
background-color: #01337a;
color: #fff;
padding: 10px;
text-align: left;
border: 1px solid #ddd;
}
td {
padding: 10px;
border: 1px solid #ddd;
}
tr:nth-child(even) {
background-color: #f2f2f2;
}
/* 在主页面CSS中添加 */
.sidebar-iframe {
position: fixed;
left: 0;
top: 0;
width: var(--sidebar-width);
height: 100vh;
border: none;
z-index: 999;
}
/* 为main-content和header添加左边距以避开iframe */
.main-content {
margin-left: var(--sidebar-width);
margin-top: var(--header-height);
}
.top-header {
left: var(--sidebar-width);
}
</style>
<script src="https://unpkg.com/vue@3/dist/vue.global.js"></script>
<style>
* {
margin: 0;
padding: 0;
box-sizing: border-box;
}
body {
font-family: 'Microsoft YaHei', Arial, sans-serif;
background: #f5f7fa;
min-height: 100vh;
padding: 20px;
}
.container {
/*max-width: 1000px;*/
/*margin: 0 auto;*/
}
.header {
background: white;
padding: 20px 30px;
border-radius: 8px;
box-shadow: 0 2px 8px rgba(0,0,0,0.1);
margin-bottom: 20px;
}
.header h1 {
color: #333;
font-size: 24px;
font-weight: 600;
}
.card {
background: white;
border-radius: 8px;
padding: 30px;
box-shadow: 0 2px 8px rgba(0,0,0,0.1);
margin-bottom: 20px;
}
.card-title {
font-size: 18px;
font-weight: 600;
color: #333;
margin-bottom: 25px;
padding-bottom: 12px;
border-bottom: 2px solid #409eff;
}
.form-group {
margin-bottom: 20px;
}
.form-label {
display: block;
margin-bottom: 8px;
color: #333;
font-weight: 500;
font-size: 14px;
}
.form-label .required {
color: #f56c6c;
margin-left: 4px;
}
.form-control {
width: 100%;
padding: 10px 12px;
border: 1px solid #dcdfe6;
border-radius: 6px;
font-size: 14px;
transition: border-color 0.3s;
}
.form-control:focus {
outline: none;
border-color: #409eff;
}
.form-row {
display: grid;
grid-template-columns: 1fr 1fr;
gap: 20px;
}
.form-actions {
display: flex;
justify-content: flex-end;
gap: 15px;
margin-top: 30px;
padding-top: 20px;
border-top: 1px solid #e4e7ed;
}
.btn {
padding: 10px 24px;
border: none;
border-radius: 6px;
cursor: pointer;
font-size: 14px;
transition: all 0.3s;
font-weight: 500;
}
.btn-primary {
background: #409eff;
color: white;
}
.btn-primary:hover {
background: #66b1ff;
}
.btn-default {
background: #f5f7fa;
color: #606266;
border: 1px solid #dcdfe6;
}
.btn-default:hover {
background: #ecf5ff;
color: #409eff;
border-color: #409eff;
}
.form-hint {
font-size: 12px;
color: #909399;
margin-top: 5px;
}
.switch {
position: relative;
display: inline-block;
width: 50px;
height: 24px;
}
.switch input {
opacity: 0;
width: 0;
height: 0;
}
.slider {
position: absolute;
cursor: pointer;
top: 0;
left: 0;
right: 0;
bottom: 0;
background-color: #ccc;
transition: .4s;
border-radius: 24px;
}
.slider:before {
position: absolute;
content: "";
height: 18px;
width: 18px;
left: 3px;
bottom: 3px;
background-color: white;
transition: .4s;
border-radius: 50%;
}
input:checked + .slider {
background-color: #409eff;
}
input:checked + .slider:before {
transform: translateX(26px);
}
</style>
</head>
<body>
<div class="app-container">
<div id="sidebar-container"></div>
<header class="top-header">
<div class="header-left">
<div class="breadcrumb">
<span>首页</span>
<span class="breadcrumb-separator">/</span>
<span class="breadcrumb-current">设备档案</span>
</div>
</div>
<div class="header-right">
<button class="header-icon-btn" title="通知">
<svg class="nav-icon" viewBox="0 0 20 20">
<path d="M10 2a6 6 0 00-6 6v3.586l-.707.707A1 1 0 004 14h12a1 1 0 00.707-1.707L16 11.586V8a6 6 0 00-6-6zM10 18a3 3 0 01-3-3h6a3 3 0 01-3 3z"/>
</svg>
<span class="notification-badge"></span>
</button>
<div class="lang-switcher">
<button class="lang-btn active">中文</button>
<button class="lang-btn">EN</button>
</div>
<div class="user-avatar"></div>
</div>
</header>
<div class="main-content" style="position: relative;">
<div id="app">
<div class="container">
<div class="header">
<h1>配件费用标准{{ isEdit ? '编辑' : '新增' }}</h1>
</div>
<div class="card">
<div class="card-title">配件费用标准{{ isEdit ? '编辑' : '新增' }}</div>
<form @submit.prevent="handleSubmit">
<div class="form-row">
<div class="form-group">
<label class="form-label">零件编号 <span class="required">*</span></label>
<input
type="text"
v-model="form.partNo"
class="form-control"
placeholder="请输入零件编号"
required
/>
</div>
<div class="form-group">
<label class="form-label">零件名称 <span class="required">*</span></label>
<input
type="text"
v-model="form.partName"
class="form-control"
placeholder="请输入零件名称"
required
/>
</div>
</div>
<div class="form-row">
<div class="form-group">
<label class="form-label">型号规格 <span class="required">*</span></label>
<input
type="text"
v-model="form.specification"
class="form-control"
placeholder="请输入型号规格"
required
/>
</div>
<div class="form-group">
<label class="form-label">单位 <span class="required">*</span></label>
<input
type="text"
v-model="form.unit"
class="form-control"
placeholder="如:块、条、台等"
required
/>
</div>
</div>
<!--<div class="form-row">
<div class="form-group">
<label class="form-label">标准单价 <span class="required">*</span></label>
<input
type="number"
v-model.number="form.price"
class="form-control"
placeholder="请输入标准单价"
step="0.01"
min="0"
required
/>
<div class="form-hint">单位:元</div>
</div>
&lt;!&ndash; <div class="form-group">
<label class="form-label">是否含税</label>
<div style="margin-top: 8px;">
<label class="switch">
<input type="checkbox" v-model="form.taxIncluded">
<span class="slider"></span>
</label>
<span style="margin-left: 10px; color: #606266;">{{ form.taxIncluded ? '含税' : '不含税' }}</span>
</div>
</div> &ndash;&gt;
</div>-->
<div class="form-row">
<div class="form-group">
<label class="form-label">生效时间 <span class="required">*</span></label>
<input
type="date"
v-model="form.effectiveDate"
class="form-control"
required
/>
</div>
<div class="form-group">
<label class="form-label">寿命周期</label>
<input
type="number"
v-model.number="form.lifecycle"
class="form-control"
placeholder="请输入寿命周期(月)"
/>
<div class="form-hint">单位:月</div>
</div>
</div>
<div class="form-row">
<div class="form-group">
<label class="form-label">保养周期</label>
<input
type="number"
v-model.number="form.maintenanceCycle"
class="form-control"
placeholder="请输入保养周期(天)"
/>
<div class="form-hint">单位:天</div>
</div>
<div class="form-group">
<label class="form-label">备注</label>
<textarea
v-model="form.remark"
class="form-control"
rows="4"
placeholder="请输入备注信息"
></textarea>
</div>
</div>
<div class="form-actions">
<button type="button" class="btn btn-default" @click="handleCancel">取消</button>
<button type="submit" class="btn btn-primary">保存</button>
</div>
</form>
</div>
</div>
</div>
<script>
const { createApp } = Vue;
createApp({
data() {
const urlParams = new URLSearchParams(window.location.search);
const action = urlParams.get('action');
const id = urlParams.get('id');
return {
isEdit: action === 'edit',
form: {
partNo: '',
partName: '',
specification: '',
unit: '',
price: null,
taxIncluded: true,
effectiveDate: '',
lifecycle: null,
maintenanceCycle: null,
remark: ''
}
}
},
mounted() {
if (this.isEdit) {
const urlParams = new URLSearchParams(window.location.search);
const id = urlParams.get('id');
// 模拟加载数据
if (id === '1') {
this.form = {
partNo: 'P001',
partName: '服务器硬盘',
specification: '2TB SATA',
unit: '块',
price: 800,
taxIncluded: true,
effectiveDate: '2024-01-01',
lifecycle: 60,
maintenanceCycle: 30,
remark: '标准服务器硬盘'
};
}
}
},
methods: {
handleSubmit() {
alert(this.isEdit ? '保存成功!' : '新增成功!');
window.location.href = '零件管理.html';
},
handleCancel() {
if (confirm('确定要取消吗?未保存的数据将丢失。')) {
window.location.href = '零件管理.html';
}
}
}
}).mount('#app');
</script>
</div>
</div>
</body>
<script src="./js.js"></script>
<script>
let importstr = document.getElementById('import')
let uploadstr = document.getElementById('batch-upload-modal')
let close = document.getElementById('close-batch-upload-modal')
let cancel = document.getElementById('cancel-batch-upload-btn')
uploadstr.style.display = 'none'
importstr.addEventListener('click', function () {
uploadstr.style.display = 'flex'
})
uploadstr.addEventListener('click', function (e) {
// 阻止事件冒泡,只有点击模态框背景时才关闭
if (e.target === uploadstr) {
uploadstr.style.display = 'none'
}
})
close.addEventListener('click', function () {
uploadstr.style.display = 'none'
})
cancel.addEventListener('click', function () {
uploadstr.style.display = 'none'
})
</script>
</html>
\ No newline at end of file
<!DOCTYPE html>
<!DOCTYPE html>
......@@ -1333,7 +1333,7 @@
<div class="card" style="padding: 20px;">
<!-- <div class="toolbar">
<div class="card-title">件费用标准列表</div>
<div class="card-title">件费用标准列表</div>
<div style="display: flex; gap: 10px;">
<button class="btn btn-success" @click="handleImport">批量导入</button>
<button class="btn btn-primary" @click="handleAdd">+ 新增零件</button>
......@@ -1341,11 +1341,11 @@
</div>-->
<div class="page-header">
<div>
<h1 class="page-title" data-i18n="title">配件管理</h1>
<h1 class="page-title" data-i18n="title">配件报价</h1>
</div>
<div class="toolbar" style="display:flex;justify-content: end;margin-bottom: 20px;">
<button class="btn btn-primary" style="text-align: right;padding: 8px 28px;margin-right: 4px;" @click="handleAdd">批量导入</button>
<button class="btn btn-primary" style="text-align: right;padding: 8px 28px;" @click="handleAdd">+ 新增</button>
<button class="btn btn-primary" style="text-align: right;padding: 8px 28px;" @click="handleAdd">+ 新增</button>
</div>
</div>
......@@ -1358,6 +1358,8 @@
<th>标准单价</th>
<th>单位</th>
<th>适用设备</th>
<th>寿命周期</th>
<th>保养周期</th>
<th>状态</th>
<th>操作</th>
</tr>
......@@ -1370,6 +1372,8 @@
<td>¥{{ item.price }}</td>
<td>{{ item.unit }}</td>
<td>{{ item.applicableEquipment }}</td>
<td>{{ item.lifecycle }} 月</td>
<td>{{ item.maintenanceCycle }} 天</td>
<td>
<span :class="item.status === '启用' ? 'badge badge-success' : 'badge badge-danger'">
{{ item.status }}
......@@ -1402,6 +1406,8 @@
price: 800,
unit: '块',
applicableEquipment: '服务器',
lifecycle: 60,
maintenanceCycle: 30,
status: '启用'
},
{
......@@ -1412,6 +1418,8 @@
price: 600,
unit: '条',
applicableEquipment: '服务器/工作站',
lifecycle: 36,
maintenanceCycle: 90,
status: '启用'
},
{
......@@ -1422,6 +1430,8 @@
price: 2000,
unit: '台',
applicableEquipment: '网络设备',
lifecycle: 120,
maintenanceCycle: 180,
status: '启用'
},
{
......@@ -1432,6 +1442,8 @@
price: 3500,
unit: '台',
applicableEquipment: '电源设备',
lifecycle: 120,
maintenanceCycle: 30,
status: '启用'
}
]
......
<!DOCTYPE html>
<!DOCTYPE html>
......@@ -1507,11 +1507,11 @@
<div id="app">
<div class="container">
<div class="header">
<h1>件费用标准{{ isEdit ? '编辑' : '新增' }}</h1>
<h1>件费用标准{{ isEdit ? '编辑' : '新增' }}</h1>
</div>
<div class="card">
<div class="card-title">件费用标准{{ isEdit ? '编辑' : '新增' }}</div>
<div class="card-title">件费用标准{{ isEdit ? '编辑' : '新增' }}</div>
<form @submit.prevent="handleSubmit">
<div class="form-row">
<div class="form-group">
......@@ -1585,6 +1585,7 @@
</div> -->
</div>
<div class="form-row">
<div class="form-group">
<label class="form-label">生效时间 <span class="required">*</span></label>
<input
......@@ -1594,7 +1595,29 @@
required
/>
</div>
<div class="form-group">
<label class="form-label">寿命周期</label>
<input
type="number"
v-model.number="form.lifecycle"
class="form-control"
placeholder="请输入寿命周期(月)"
/>
<div class="form-hint">单位:月</div>
</div>
</div>
<div class="form-row">
<div class="form-group">
<label class="form-label">保养周期</label>
<input
type="number"
v-model.number="form.maintenanceCycle"
class="form-control"
placeholder="请输入保养周期(天)"
/>
<div class="form-hint">单位:天</div>
</div>
<div class="form-group">
<label class="form-label">备注</label>
<textarea
......@@ -1604,6 +1627,7 @@
placeholder="请输入备注信息"
></textarea>
</div>
</div>
<div class="form-actions">
<button type="button" class="btn btn-default" @click="handleCancel">取消</button>
......@@ -1633,6 +1657,8 @@
price: null,
taxIncluded: true,
effectiveDate: '',
lifecycle: null,
maintenanceCycle: null,
remark: ''
}
}
......@@ -1651,6 +1677,8 @@
price: 800,
taxIncluded: true,
effectiveDate: '2024-01-01',
lifecycle: 60,
maintenanceCycle: 30,
remark: '标准服务器硬盘'
};
}
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment