user-management.html 27 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731
  1. <!DOCTYPE html>
  2. <html lang="zh-CN" class="iframe-content">
  3. <head>
  4. <meta charset="UTF-8">
  5. <meta name="viewport" content="width=device-width, initial-scale=1.0">
  6. <title>用户管理 - 爱智农</title>
  7. <link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/tailwindcss@2.2.19/dist/tailwind.min.css">
  8. <link rel="stylesheet" href="https://at.alicdn.com/t/font_3114978_qe0b39no76.css">
  9. <link rel="stylesheet" href="../assets/css/global.css">
  10. <style>
  11. body {
  12. font-family: "PingFang SC", "Microsoft YaHei", sans-serif;
  13. background-color: #f5f7f9;
  14. color: #333;
  15. }
  16. .page-container {
  17. padding: 20px;
  18. }
  19. .card {
  20. background-color: white;
  21. border-radius: 8px;
  22. box-shadow: 0 2px 8px rgba(0,0,0,0.05);
  23. }
  24. .table-container {
  25. position: relative;
  26. position: relative;
  27. overflow-x: auto;
  28. position: relative;
  29. }
  30. table {
  31. width: 100%;
  32. border-collapse: separate;
  33. border-spacing: 0;
  34. }
  35. th {
  36. white-space: nowrap;
  37. position: relative;
  38. overflow: visible;
  39. max-width: none;
  40. text-overflow: clip;
  41. white-space: nowrap;
  42. position: relative;
  43. background-color: #f9fafb;
  44. padding: 12px 16px;
  45. text-align: left;
  46. font-weight: 500;
  47. color: #6b7280;
  48. border-bottom: 1px solid #e5e7eb;
  49. white-space: nowrap;
  50. position: relative;
  51. }
  52. td {
  53. white-space: nowrap;
  54. max-width: 200px;
  55. overflow: hidden;
  56. text-overflow: ellipsis;
  57. white-space: nowrap;
  58. max-width: 200px;
  59. overflow: hidden;
  60. text-overflow: ellipsis;
  61. padding: 12px 16px;
  62. border-bottom: 1px solid #e5e7eb;
  63. white-space: nowrap;
  64. max-width: 200px;
  65. overflow: hidden;
  66. text-overflow: ellipsis;
  67. }
  68. /* 固定最后一列(操作列)样式 */
  69. .table-fixed-right {
  70. position: relative;
  71. }
  72. .table-fixed-right th:last-child,
  73. .table-fixed-right td:last-child {
  74. position: sticky;
  75. right: 0;
  76. z-index: 2;
  77. background-color: white;
  78. box-shadow: -5px 0 5px -5px rgba(0, 0, 0, 0.1);
  79. }
  80. .table-fixed-right th:last-child {
  81. background-color: #f9fafb;
  82. }
  83. /* 表格滚动控件 */
  84. .table-scroll-controls {
  85. display: none;
  86. position: absolute;
  87. top: 50%;
  88. transform: translateY(-50%);
  89. width: 100%;
  90. pointer-events: none;
  91. z-index: 3;
  92. }
  93. .table-scroll-btn {
  94. position: absolute;
  95. width: 32px;
  96. height: 32px;
  97. border-radius: 50%;
  98. background-color: rgba(255, 255, 255, 0.9);
  99. color: #4CAF50;
  100. border: 1px solid #e0e0e0;
  101. display: flex;
  102. align-items: center;
  103. justify-content: center;
  104. cursor: pointer;
  105. pointer-events: auto;
  106. box-shadow: 0 2px 5px rgba(0, 0, 0, 0.1);
  107. z-index: 4;
  108. }
  109. .table-scroll-left {
  110. left: 10px;
  111. }
  112. .table-scroll-right {
  113. right: 10px;
  114. }
  115. .has-overflow .table-scroll-controls {
  116. display: block;
  117. }
  118. tr:hover {
  119. background-color: #f9fafb;
  120. }
  121. tr:hover td:last-child {
  122. background-color: #f9fafb;
  123. }
  124. .btn {
  125. display: inline-flex;
  126. align-items: center;
  127. justify-content: center;
  128. padding: 8px 16px;
  129. border-radius: 4px;
  130. font-weight: 500;
  131. cursor: pointer;
  132. transition: all 0.2s;
  133. }
  134. .btn-primary {
  135. background-color: #4CAF50;
  136. color: white;
  137. }
  138. .btn-primary:hover {
  139. background-color: #388E3C;
  140. }
  141. .btn-default {
  142. background-color: white;
  143. border: 1px solid #d1d5db;
  144. color: #374151;
  145. }
  146. .btn-default:hover {
  147. background-color: #f9fafb;
  148. }
  149. .btn-danger {
  150. background-color: #ef4444;
  151. color: white;
  152. }
  153. .btn-danger:hover {
  154. background-color: #dc2626;
  155. }
  156. .btn-sm {
  157. padding: 4px 8px;
  158. font-size: 12px;
  159. }
  160. .btn-icon {
  161. margin-right: 4px;
  162. }
  163. .search-box {
  164. display: flex;
  165. gap: 8px;
  166. }
  167. .input {
  168. padding: 8px 12px;
  169. border: 1px solid #d1d5db;
  170. border-radius: 4px;
  171. flex-grow: 1;
  172. }
  173. .input:focus {
  174. outline: none;
  175. border-color: #4CAF50;
  176. box-shadow: 0 0 0 2px rgba(76, 175, 80, 0.2);
  177. }
  178. .select {
  179. padding: 8px 12px;
  180. border: 1px solid #d1d5db;
  181. border-radius: 4px;
  182. background-color: white;
  183. }
  184. .modal-overlay {
  185. position: fixed;
  186. top: 0;
  187. left: 0;
  188. right: 0;
  189. bottom: 0;
  190. background-color: rgba(0, 0, 0, 0.5);
  191. display: flex;
  192. align-items: center;
  193. justify-content: center;
  194. z-index: 50;
  195. display: none;
  196. }
  197. .modal {
  198. background-color: white;
  199. border-radius: 8px;
  200. width: 100%;
  201. max-width: 500px;
  202. box-shadow: 0 4px 6px -1px rgba(0, 0, 0, 0.1), 0 2px 4px -1px rgba(0, 0, 0, 0.06);
  203. }
  204. .modal-header {
  205. padding: 16px 24px;
  206. border-bottom: 1px solid #e5e7eb;
  207. display: flex;
  208. align-items: center;
  209. justify-content: space-between;
  210. }
  211. .modal-title {
  212. font-size: 18px;
  213. font-weight: 500;
  214. }
  215. .modal-close {
  216. cursor: pointer;
  217. font-size: 20px;
  218. }
  219. .modal-body {
  220. padding: 24px;
  221. }
  222. .modal-footer {
  223. padding: 16px 24px;
  224. border-top: 1px solid #e5e7eb;
  225. display: flex;
  226. justify-content: flex-end;
  227. gap: 8px;
  228. }
  229. .form-group {
  230. margin-bottom: 16px;
  231. }
  232. .form-label {
  233. display: block;
  234. margin-bottom: 4px;
  235. font-weight: 500;
  236. }
  237. .form-input {
  238. width: 100%;
  239. padding: 8px 12px;
  240. border: 1px solid #d1d5db;
  241. border-radius: 4px;
  242. }
  243. .form-input:focus {
  244. outline: none;
  245. border-color: #4CAF50;
  246. box-shadow: 0 0 0 2px rgba(76, 175, 80, 0.2);
  247. }
  248. .badge {
  249. display: inline-block;
  250. padding: 2px 8px;
  251. border-radius: 9999px;
  252. font-size: 12px;
  253. font-weight: 500;
  254. }
  255. .badge-success {
  256. background-color: #d1fae5;
  257. color: #065f46;
  258. }
  259. .badge-warning {
  260. background-color: #fef3c7;
  261. color: #92400e;
  262. }
  263. .pagination {
  264. display: flex;
  265. align-items: center;
  266. justify-content: flex-end;
  267. gap: 4px;
  268. }
  269. .pagination-item {
  270. display: inline-flex;
  271. align-items: center;
  272. justify-content: center;
  273. width: 32px;
  274. height: 32px;
  275. border-radius: 4px;
  276. cursor: pointer;
  277. transition: all 0.2s;
  278. }
  279. .pagination-item:hover {
  280. background-color: #f3f4f6;
  281. }
  282. .pagination-item.active {
  283. background-color: #4CAF50;
  284. color: white;
  285. }
  286. .pagination-item.disabled {
  287. color: #9ca3af;
  288. cursor: not-allowed;
  289. }
  290. </style>
  291. </head>
  292. <body>
  293. <div class="page-container responsive-container">
  294. <div class="flex justify-between items-center mb-6">
  295. <h1 class="text-2xl font-bold">用户管理</h1>
  296. <button class="btn btn-primary" id="addUserBtn">
  297. <i class="iconfont icon-plus btn-icon"></i>
  298. 新增用户
  299. </button>
  300. </div>
  301. <div class="card p-6 mb-6">
  302. <div class="flex flex-wrap gap-4">
  303. <div class="search-box flex-grow">
  304. <input type="text" class="input" placeholder="请输入用户名/姓名/手机号">
  305. <button class="btn btn-primary">
  306. <i class="iconfont icon-search btn-icon"></i>
  307. 搜索
  308. </button>
  309. <button class="btn btn-default">
  310. <i class="iconfont icon-reload btn-icon"></i>
  311. 重置
  312. </button>
  313. </div>
  314. <div class="flex gap-2">
  315. <select class="select">
  316. <option value="">所有角色</option>
  317. <option value="admin">管理员</option>
  318. <option value="operator">操作员</option>
  319. <option value="viewer">查看者</option>
  320. </select>
  321. <select class="select">
  322. <option value="">所有状态</option>
  323. <option value="1">启用</option>
  324. <option value="0">禁用</option>
  325. </select>
  326. </div>
  327. </div>
  328. </div>
  329. <div class="card">
  330. <div class="table-container">
  331. <div class="table-scroll-controls">
  332. <button class="table-scroll-btn table-scroll-left">
  333. <i class="iconfont icon-left"></i>
  334. </button>
  335. <button class="table-scroll-btn table-scroll-right">
  336. <i class="iconfont icon-right"></i>
  337. </button>
  338. </div>
  339. <table class="table-fixed-right">
  340. <thead>
  341. <tr>
  342. <th class="min-w-[120px]">用户名</th>
  343. <th class="min-w-[100px]">姓名</th>
  344. <th class="min-w-[120px]">手机号</th>
  345. <th class="min-w-[180px]">邮箱</th>
  346. <th class="min-w-[100px]">角色</th>
  347. <th class="min-w-[100px]">部门</th>
  348. <th class="min-w-[80px]">状态</th>
  349. <th class="min-w-[180px]">创建时间</th>
  350. <th class="min-w-[150px]">操作</th>
  351. </tr>
  352. </thead>
  353. <tbody>
  354. <tr>
  355. <td>admin</td>
  356. <td>系统管理员</td>
  357. <td>13800138000</td>
  358. <td>admin@aizhinong.com</td>
  359. <td>管理员</td>
  360. <td>技术部</td>
  361. <td><span class="badge badge-success">启用</span></td>
  362. <td>2023-01-01 12:00:00</td>
  363. <td>
  364. <div class="flex gap-2">
  365. <button class="btn btn-default btn-sm edit-btn" data-id="1">
  366. <i class="iconfont icon-edit btn-icon"></i>
  367. 编辑
  368. </button>
  369. <button class="btn btn-danger btn-sm">
  370. <i class="iconfont icon-delete btn-icon"></i>
  371. 删除
  372. </button>
  373. </div>
  374. </td>
  375. </tr>
  376. <tr>
  377. <td>operator</td>
  378. <td>张三</td>
  379. <td>13900139000</td>
  380. <td>zhangsan@aizhinong.com</td>
  381. <td>操作员</td>
  382. <td>运营部</td>
  383. <td><span class="badge badge-success">启用</span></td>
  384. <td>2023-01-02 10:30:00</td>
  385. <td>
  386. <div class="flex gap-2">
  387. <button class="btn btn-default btn-sm edit-btn" data-id="2">
  388. <i class="iconfont icon-edit btn-icon"></i>
  389. 编辑
  390. </button>
  391. <button class="btn btn-danger btn-sm">
  392. <i class="iconfont icon-delete btn-icon"></i>
  393. 删除
  394. </button>
  395. </div>
  396. </td>
  397. </tr>
  398. <tr>
  399. <td>viewer</td>
  400. <td>李四</td>
  401. <td>13700137000</td>
  402. <td>lisi@aizhinong.com</td>
  403. <td>查看者</td>
  404. <td>市场部</td>
  405. <td><span class="badge badge-warning">禁用</span></td>
  406. <td>2023-01-03 09:15:00</td>
  407. <td>
  408. <div class="flex gap-2">
  409. <button class="btn btn-default btn-sm edit-btn" data-id="3">
  410. <i class="iconfont icon-edit btn-icon"></i>
  411. 编辑
  412. </button>
  413. <button class="btn btn-danger btn-sm">
  414. <i class="iconfont icon-delete btn-icon"></i>
  415. 删除
  416. </button>
  417. </div>
  418. </td>
  419. </tr>
  420. <tr>
  421. <td>tester</td>
  422. <td>王五</td>
  423. <td>13600136000</td>
  424. <td>wangwu@aizhinong.com</td>
  425. <td>操作员</td>
  426. <td>测试部</td>
  427. <td><span class="badge badge-success">启用</span></td>
  428. <td>2023-01-04 14:20:00</td>
  429. <td>
  430. <div class="flex gap-2">
  431. <button class="btn btn-default btn-sm edit-btn" data-id="4">
  432. <i class="iconfont icon-edit btn-icon"></i>
  433. 编辑
  434. </button>
  435. <button class="btn btn-danger btn-sm">
  436. <i class="iconfont icon-delete btn-icon"></i>
  437. 删除
  438. </button>
  439. </div>
  440. </td>
  441. </tr>
  442. <tr>
  443. <td>guest</td>
  444. <td>访客</td>
  445. <td>13500135000</td>
  446. <td>guest@aizhinong.com</td>
  447. <td>查看者</td>
  448. <td>-</td>
  449. <td><span class="badge badge-success">启用</span></td>
  450. <td>2023-01-05 16:45:00</td>
  451. <td>
  452. <div class="flex gap-2">
  453. <button class="btn btn-default btn-sm edit-btn" data-id="5">
  454. <i class="iconfont icon-edit btn-icon"></i>
  455. 编辑
  456. </button>
  457. <button class="btn btn-danger btn-sm">
  458. <i class="iconfont icon-delete btn-icon"></i>
  459. 删除
  460. </button>
  461. </div>
  462. </td>
  463. </tr>
  464. </tbody>
  465. </table>
  466. </div>
  467. <div class="p-4 flex justify-between items-center">
  468. <div class="text-sm text-gray-500">
  469. 共 <span class="font-medium">5</span> 条记录,每页 <span class="font-medium">10</span> 条
  470. </div>
  471. <div class="pagination">
  472. <div class="pagination-item disabled">
  473. <i class="iconfont icon-left"></i>
  474. </div>
  475. <div class="pagination-item active">1</div>
  476. <div class="pagination-item">2</div>
  477. <div class="pagination-item">3</div>
  478. <div class="pagination-item">
  479. <i class="iconfont icon-right"></i>
  480. </div>
  481. </div>
  482. </div>
  483. </div>
  484. </div>
  485. <!-- 用户表单弹窗 -->
  486. <div class="modal-overlay" id="userModal">
  487. <div class="modal">
  488. <div class="modal-header">
  489. <h3 class="modal-title" id="modalTitle">新增用户</h3>
  490. <div class="modal-close" id="closeModal">&times;</div>
  491. </div>
  492. <div class="modal-body">
  493. <form id="userForm">
  494. <div class="form-group">
  495. <label class="form-label" for="username">用户名</label>
  496. <input type="text" id="username" class="form-input" placeholder="请输入用户名">
  497. </div>
  498. <div class="form-group">
  499. <label class="form-label" for="realname">姓名</label>
  500. <input type="text" id="realname" class="form-input" placeholder="请输入姓名">
  501. </div>
  502. <div class="form-group">
  503. <label class="form-label" for="password">密码</label>
  504. <input type="password" id="password" class="form-input" placeholder="请输入密码">
  505. </div>
  506. <div class="form-group">
  507. <label class="form-label" for="phone">手机号</label>
  508. <input type="text" id="phone" class="form-input" placeholder="请输入手机号">
  509. </div>
  510. <div class="form-group">
  511. <label class="form-label" for="email">邮箱</label>
  512. <input type="email" id="email" class="form-input" placeholder="请输入邮箱">
  513. </div>
  514. <div class="form-group">
  515. <label class="form-label" for="role">角色</label>
  516. <select id="role" class="form-input">
  517. <option value="">请选择角色</option>
  518. <option value="admin">管理员</option>
  519. <option value="operator">操作员</option>
  520. <option value="viewer">查看者</option>
  521. </select>
  522. </div>
  523. <div class="form-group">
  524. <label class="form-label" for="department">部门</label>
  525. <select id="department" class="form-input">
  526. <option value="">请选择部门</option>
  527. <option value="tech">技术部</option>
  528. <option value="operation">运营部</option>
  529. <option value="market">市场部</option>
  530. <option value="test">测试部</option>
  531. </select>
  532. </div>
  533. <div class="form-group">
  534. <label class="form-label" for="status">状态</label>
  535. <select id="status" class="form-input">
  536. <option value="1">启用</option>
  537. <option value="0">禁用</option>
  538. </select>
  539. </div>
  540. <div class="form-group">
  541. <label class="form-label" for="remark">备注</label>
  542. <textarea id="remark" class="form-input" rows="3" placeholder="请输入备注信息"></textarea>
  543. </div>
  544. </form>
  545. </div>
  546. <div class="modal-footer">
  547. <button class="btn btn-default" id="cancelBtn">取消</button>
  548. <button class="btn btn-primary" id="saveBtn">保存</button>
  549. </div>
  550. </div>
  551. </div>
  552. <script>
  553. document.addEventListener('DOMContentLoaded', function() {
  554. const userModal = document.getElementById('userModal');
  555. const modalTitle = document.getElementById('modalTitle');
  556. const addUserBtn = document.getElementById('addUserBtn');
  557. const closeModal = document.getElementById('closeModal');
  558. const cancelBtn = document.getElementById('cancelBtn');
  559. const saveBtn = document.getElementById('saveBtn');
  560. const editBtns = document.querySelectorAll('.edit-btn');
  561. const userForm = document.getElementById('userForm');
  562. // 初始化表格滚动功能
  563. function initTableScroll() {
  564. const tableContainer = document.querySelector('.table-container');
  565. const scrollLeftBtn = document.querySelector('.table-scroll-left');
  566. const scrollRightBtn = document.querySelector('.table-scroll-right');
  567. // 检查表格是否需要水平滚动
  568. function checkTableOverflow() {
  569. if (tableContainer.scrollWidth > tableContainer.clientWidth) {
  570. tableContainer.classList.add('has-overflow');
  571. } else {
  572. tableContainer.classList.remove('has-overflow');
  573. }
  574. }
  575. // 左右滚动按钮点击事件
  576. scrollLeftBtn.addEventListener('click', function() {
  577. tableContainer.scrollLeft -= 150;
  578. });
  579. scrollRightBtn.addEventListener('click', function() {
  580. tableContainer.scrollLeft += 150;
  581. });
  582. // 初始检查和窗口大小变化时检查
  583. checkTableOverflow();
  584. window.addEventListener('resize', checkTableOverflow);
  585. // 滚动事件处理
  586. tableContainer.addEventListener('scroll', function() {
  587. // 根据滚动位置显示/隐藏滚动按钮
  588. if (tableContainer.scrollLeft <= 10) {
  589. scrollLeftBtn.style.opacity = '0.5';
  590. } else {
  591. scrollLeftBtn.style.opacity = '1';
  592. }
  593. if (tableContainer.scrollLeft >= tableContainer.scrollWidth - tableContainer.clientWidth - 10) {
  594. scrollRightBtn.style.opacity = '0.5';
  595. } else {
  596. scrollRightBtn.style.opacity = '1';
  597. }
  598. });
  599. // 初始触发滚动事件,设置初始按钮状态
  600. tableContainer.dispatchEvent(new Event('scroll'));
  601. }
  602. // 初始化表格滚动
  603. initTableScroll();
  604. // 打开新增用户弹窗
  605. addUserBtn.addEventListener('click', function() {
  606. modalTitle.textContent = '新增用户';
  607. userForm.reset();
  608. userModal.style.display = 'flex';
  609. });
  610. // 打开编辑用户弹窗
  611. editBtns.forEach(btn => {
  612. btn.addEventListener('click', function() {
  613. const userId = this.getAttribute('data-id');
  614. modalTitle.textContent = '编辑用户';
  615. // 模拟获取用户数据
  616. // 实际应用中应该通过API获取
  617. if (userId === '1') {
  618. document.getElementById('username').value = 'admin';
  619. document.getElementById('realname').value = '系统管理员';
  620. document.getElementById('phone').value = '13800138000';
  621. document.getElementById('email').value = 'admin@aizhinong.com';
  622. document.getElementById('role').value = 'admin';
  623. document.getElementById('department').value = 'tech';
  624. document.getElementById('status').value = '1';
  625. }
  626. userModal.style.display = 'flex';
  627. });
  628. });
  629. // 关闭弹窗
  630. function closeUserModal() {
  631. userModal.style.display = 'none';
  632. }
  633. closeModal.addEventListener('click', closeUserModal);
  634. cancelBtn.addEventListener('click', closeUserModal);
  635. // 保存用户
  636. saveBtn.addEventListener('click', function() {
  637. // 模拟保存
  638. alert('用户信息保存成功!');
  639. closeUserModal();
  640. });
  641. // 点击弹窗外部关闭弹窗
  642. userModal.addEventListener('click', function(e) {
  643. if (e.target === userModal) {
  644. closeUserModal();
  645. }
  646. });
  647. });
  648. </script>
  649. </body>
  650. </html>