Digital Office Automation System
Du kan inte välja fler än 25 ämnen Ämnen måste starta med en bokstav eller siffra, kan innehålla bindestreck ('-') och vara max 35 tecken långa.

index.vue 21KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811912012112212312412512612712812913013113213313413513613713813914014114214314414514614714814915015115215315415515615715815916016116216316416516616716816917017117217317417517617717817918018118218318418518618718818919019119219319419519619719819920020120220320420520620720820921021121221321421521621721821922022122222322422522622722822923023123223323423523623723823924024124224324424524624724824925025125225325425525625725825926026126226326426526626726826927027127227327427527627727827928028128228328428528628728828929029129229329429529629729829930030130230330430530630730830931031131231331431531631731831932032132232332432532632732832933033133233333433533633733833934034134234334434534634734834935035135235335435535635735835936036136236336436536636736836937037137237337437537637737837938038138238338438538638738838939039139239339439539639739839940040140240340440540640740840941041141241341441541641741841942042142242342442542642742842943043143243343443543643743843944044144244344444544644744844945045145245345445545645745845946046146246346446546646746846947047147247347447547647747847948048148248348448548648748848949049149249349449549649749849950050150250350450550650750850951051151251351451551651751851952052152252352452552652752852953053153253353453553653753853954054154254354454554654754854955055155255355455555655755855956056156256356456556656756856957057157257357457557657757857958058158258358458558658758858959059159259359459559659759859960060160260360460560660760860961061161261361461561661761861962062162262362462562662762862963063163263363463563663763863964064164264364464564664764864965065165265365465565665765865966066166266366466566666766866967067167267367467567667767867968068168268368468568668768868969069169269369469569669769869970070170270370470570670770870971071171271371471571671771871972072172272372472572672772872973073173273373473573673773873974074174274374474574674774874975075175275375475575675775875976076176276376476576676776876977077177277377477577677777877978078178278378478578678778878979079179279379479579679779879980080180280380480580680780880981081181281381481581681781881982082182282382482582682782882983083183283383483583683783883984084184284384484584684784884985085185285385485585685785885986086186286386486586686786886987087187287387487587687787887988088188288388488588688788888989089189289389489589689789889990090190290390490590690790890991091191291391491591691791891992092192292392492592692792892993093193293393493593693793893994094194294394494594694794894995095195295395495595695795895996096196296396496596696796896997097197297397497597697797897998098198298398498598698798898999099199299399499599699799899910001001100210031004100510061007100810091010101110121013101410151016101710181019102010211022102310241025102610271028102910301031103210331034103510361037103810391040104110421043104410451046104710481049105010511052105310541055105610571058105910601061106210631064
  1. <template>
  2. <div class="app-container">
  3. <el-row>
  4. <el-form
  5. v-show="showSearch"
  6. ref="queryForm"
  7. :model="queryParams"
  8. size="small"
  9. :inline="true"
  10. class="app-container--search"
  11. >
  12. <el-form-item label="用户id" prop="userName">
  13. <el-input
  14. v-model="queryParams.userName"
  15. placeholder="请输入规则名称"
  16. clearable
  17. @keyup.enter.native="handleQuery"
  18. />
  19. </el-form-item>
  20. <el-form-item label="用户名称" prop="nickName">
  21. <el-input
  22. v-model="queryParams.nickName"
  23. placeholder="请输入规则名称"
  24. clearable
  25. @keyup.enter.native="handleQuery"
  26. />
  27. </el-form-item>
  28. <el-form-item>
  29. <el-button
  30. type="primary"
  31. icon="el-icon-search"
  32. size="mini"
  33. @click="handleQuery"
  34. >搜索</el-button>
  35. <el-button
  36. icon="el-icon-refresh"
  37. size="mini"
  38. @click="resetQuery"
  39. >重置</el-button>
  40. </el-form-item>
  41. </el-form>
  42. </el-row>
  43. <el-table v-loading="loading" :data="njBalanceManageData" @selection-change="handleSelectionChange" >
  44. <!-- <el-table-column type="selection" width="55" align="center" /> -->
  45. <el-table-column label="员工编号" align="center" prop="userName" />
  46. <el-table-column label="员工姓名" align="center" prop="nickName" />
  47. <el-table-column label="所属部门" align="center" prop="deptName" />
  48. <el-table-column label="年假总额" align="center" prop="annualLeave" />
  49. <el-table-column label="已使用天数" align="center" prop="usedDay" />
  50. <el-table-column label="剩余天数" align="center" prop="unusedDay" />
  51. <el-table-column label="上年结转" align="center" prop="lastYearUnusedDay" />
  52. <el-table-column label="状态" align="center" prop="isEnable">
  53. <template slot-scope="scope">
  54. <span
  55. v-if="scope.row.isEnable == 0"
  56. style="
  57. display: inline-flex;
  58. align-items: center;
  59. justify-content: center;
  60. text-align: center;
  61. "
  62. >
  63. 清零
  64. </span>
  65. <span
  66. v-if="scope.row.isEnable == 1"
  67. style="
  68. display: inline-flex;
  69. align-items: center;
  70. justify-content: center;
  71. text-align: center;
  72. "
  73. >
  74. 有效
  75. </span>
  76. </template>
  77. </el-table-column>
  78. </el-table>
  79. <pagination
  80. v-show="total > 0"
  81. :total="total"
  82. :page.sync="queryParams.pageNum"
  83. :limit.sync="queryParams.pageSize"
  84. @pagination="getList"
  85. />
  86. </div>
  87. </template>
  88. <script>
  89. import {
  90. add,
  91. queryList,
  92. queryArea,
  93. del,
  94. delUser,
  95. test
  96. } from '@/api/nianjiaguanli/yueguanli'
  97. import index from '@/views/components/daka/index';
  98. import { time } from 'echarts';
  99. export default {
  100. name: 'yueguanli',
  101. components: { index },
  102. dicts: [
  103. 'zs_operation_warn_types',
  104. 'zs_operation_status',
  105. 'zs_operation_compare_status',
  106. 'zs_operation_platform',
  107. 'daka_check_in_status'
  108. ],
  109. data() {
  110. return {
  111. // 按钮loading
  112. buttonLoading: false,
  113. // 遮罩层
  114. loading: true,
  115. // 选中数组
  116. ids: [],
  117. // 非单个禁用
  118. single: true,
  119. // 非多个禁用
  120. multiple: true,
  121. // 显示搜索条件
  122. showSearch: true,
  123. // 总条数
  124. total: 0,
  125. // 表格数据
  126. resultList: [],
  127. // 弹出层标题
  128. title: '',
  129. // 是否显示弹出层
  130. open: false,
  131. // 图片快照时间范围
  132. daterangeWarnTime: [],
  133. // 查询参数
  134. queryParams: {
  135. pageNum: 1,
  136. pageSize: 10,
  137. userName: undefined,
  138. nickName: undefined,
  139. },
  140. // 表单参数
  141. form: {},
  142. // 结果
  143. warnResult: '',
  144. // 表单校验
  145. rules: {
  146. snapshotUrl: [
  147. { required: true, message: '图片快照不能为空', trigger: 'blur' }
  148. ]
  149. },
  150. daka_check_in_status: [{label: '正常', value: '0'},{label: '迟到', value: '1'},{label: '缺卡', value: '2'}],
  151. // 地图相关
  152. map: null,
  153. marker: null,
  154. circle: null,
  155. mapHeight: '400px',
  156. baiduMapKey: '你的百度地图API Key', // 替换为你的API Key
  157. // 表单数据
  158. formData: {
  159. id: null,
  160. name: '',
  161. lng: '116.404', // 默认经度(北京天安门)
  162. lat: '39.915', // 默认纬度(北京天安门)
  163. radius: 500, // 默认半径500米
  164. enabled: false
  165. },
  166. // 区域列表
  167. areaList: [],
  168. // 模态框状态
  169. showDeleteModal: false,
  170. currentDeletingArea: null,
  171. // 考勤组列表
  172. attendanceGroups: [],
  173. // 当前选中的考勤组ID
  174. selectedGroupId: null,
  175. // 考勤组表单数据
  176. attendanceGroup: {
  177. id: null,
  178. name: '',
  179. description: '',
  180. workDays: ['mon', 'tue', 'wed', 'thu', 'fri'],
  181. workStartTime: '09:00',
  182. workEndTime: '18:00',
  183. allowLate: false,
  184. lateRange: 15,
  185. allowEarly: false,
  186. earlyRange: 15,
  187. areaId: null,
  188. checkInType: 'location',
  189. members: [],
  190. areaName: ''
  191. },
  192. attendanceGroupModel: {
  193. id: null,
  194. name: '',
  195. description: '',
  196. workDays: ['mon', 'tue', 'wed', 'thu', 'fri'],
  197. workStartTime: '09:00',
  198. workEndTime: '18:00',
  199. allowLate: false,
  200. lateRange: 15,
  201. allowEarly: false,
  202. earlyRange: 15,
  203. areaId: null,
  204. checkInType: 'location',
  205. members: [],
  206. areaName: ''
  207. },
  208. // 工作日选项
  209. workDays: [
  210. { value: 'mon', label: '周一' },
  211. { value: 'tue', label: '周二' },
  212. { value: 'wed', label: '周三' },
  213. { value: 'thu', label: '周四' },
  214. { value: 'fri', label: '周五' },
  215. { value: 'sat', label: '周六' },
  216. { value: 'sun', label: '周日' }
  217. ],
  218. // 员工列表
  219. users: [],
  220. // 打卡区域列表
  221. checkInAreas: [],
  222. // 新建考勤组表单
  223. newGroup: {
  224. name: '',
  225. description: ''
  226. },
  227. // 新建考勤组表单规则
  228. newGroupRules: {
  229. name: [{ required: true, message: '请输入考勤组名称', trigger: 'blur' }]
  230. },
  231. // 搜索关键词
  232. userSearchKeyword: '',
  233. // 选中的用户
  234. selectedUsers: [],
  235. // 对话框状态
  236. userSelectionDialogVisible: false,
  237. showAddGroupModal: false,
  238. // 表单验证规则
  239. rules: {
  240. name: [
  241. { required: true, message: '请输入考勤组名称', trigger: 'blur' }
  242. ],
  243. workStartTime: [
  244. { required: true, message: '请选择上班时间', trigger: 'change' }
  245. ],
  246. workEndTime: [
  247. { required: true, message: '请选择下班时间', trigger: 'change' }
  248. ],
  249. areaId: [
  250. { required: true, message: '请选择打卡区域', trigger: 'change' }
  251. ]
  252. },
  253. // 编辑模式
  254. isEditMode: false,
  255. // 提示信息
  256. successMessage: '',
  257. successMessageVisible: false,
  258. calculationMethods: [{ value: 1, label: '自然年(每年1月1日统一生成)' },{ value: 2, label: '入职周年' }],
  259. rule: {
  260. id: undefined,
  261. ruleName: '',
  262. calculationMethod: 1,
  263. annualLeaveTiers: 5,
  264. validityPeriod: true,
  265. allowHalfDay: false,
  266. applicableRange: true,
  267. generationCycle: true,
  268. members:[]
  269. },
  270. annualLeaveTierss: [
  271. { value: 5, label: '入职满一年(5天)' },
  272. { value: 10, label: '入职满10年(10天)' },
  273. { value: 15, label: '入职满20年(15天)' },
  274. { value: 0, label: '默认规则(年假天数 = 入职当年剩余日历天数 / 365 × 5)' }
  275. ],
  276. njBalanceManageData: [],
  277. applicableRangeFlag: false
  278. };
  279. },
  280. computed: {
  281. // 表单验证
  282. isFormValid() {
  283. return (
  284. this.formData.name.trim() !== '' &&
  285. !isNaN(parseFloat(this.formData.lng)) &&
  286. !isNaN(parseFloat(this.formData.lat)) &&
  287. this.formData.radius >= 10 &&
  288. this.formData.radius <= 5000
  289. );
  290. },
  291. // 过滤后的用户列表
  292. filteredUsers() {
  293. // 获取不在当前考勤组中的用户
  294. const groupMemberIds = this.attendanceGroup.members.map(member => member.id);
  295. const availableUsers = this.users.filter(user =>
  296. !groupMemberIds.includes(user.id)
  297. );
  298. // 应用搜索过滤
  299. if (!this.userSearchKeyword) return availableUsers;
  300. const keyword = this.userSearchKeyword.toLowerCase();
  301. return availableUsers.filter(user =>
  302. user.name.toLowerCase().includes(keyword) ||
  303. user.employeeId.toLowerCase().includes(keyword) ||
  304. user.department.toLowerCase().includes(keyword) ||
  305. user.position.toLowerCase().includes(keyword)
  306. );
  307. }
  308. },
  309. mounted() {
  310. // 加载模拟数据
  311. // this.getList();
  312. // 加载模拟数据
  313. this.getList();
  314. },
  315. methods: {
  316. // 加载数据
  317. getList() {
  318. queryList(this.queryParams).then((response) => {
  319. console.log(response)
  320. this.njBalanceManageData = response.rows
  321. this.total = response.total
  322. this.loading = false
  323. })
  324. },
  325. /** 搜索按钮操作 */
  326. handleQuery() {
  327. this.queryParams.pageNum = 1
  328. this.getList()
  329. },
  330. /** 重置按钮操作 */
  331. resetQuery() {
  332. this.queryParams.ruleName = undefined
  333. this.resetForm('queryForm')
  334. this.handleQuery()
  335. },
  336. /** 新增按钮操作 */
  337. handleAdd() {
  338. this.open = true
  339. this.rule = {
  340. id: undefined,
  341. ruleName: '',
  342. calculationMethod: 1,
  343. annualLeaveTiers: 5,
  344. validityPeriod: true,
  345. allowHalfDay: false,
  346. applicableRange: true,
  347. generationCycle: true,
  348. members:[]
  349. }
  350. },
  351. // 创建年假规则
  352. createNewGroup() {
  353. add(this.rule).then((res) => {
  354. console.log(res)
  355. this.open = false
  356. this.applicableRangeFlag = false
  357. this.$message.success(res.msg);
  358. this.getList()
  359. })
  360. },
  361. // 编辑区域
  362. editRuleConfig(rule) {
  363. this.open = true
  364. // 复制对象,避免直接修改原始数据
  365. this.rule = { ...rule };
  366. if(!rule.applicableRange){
  367. this.applicableRangeFlag = true
  368. }
  369. },
  370. // 删除
  371. deleteRuleConfig(rule) {
  372. del(rule).then((res) => {
  373. this.getList()
  374. })
  375. },
  376. // 打开员工选择对话框
  377. openUserSelectionDialog() {
  378. this.userSelectionDialogVisible = true;
  379. this.selectedUsers = [];
  380. },
  381. // 处理适用范围
  382. handleApplicableRange(value) {
  383. if(!value){
  384. this.applicableRangeFlag = true
  385. }else{
  386. this.applicableRangeFlag = false
  387. this.selectedUsers = [];
  388. }
  389. },
  390. // 处理员工选择变化
  391. handleUserSelectionChange(selection) {
  392. console.log(selection)
  393. const newList = selection.map(item => ({
  394. ...item, // 保留原始字段
  395. // deptName: item.dept.deptName, // 新增字段,
  396. }));
  397. console.log(newList)
  398. this.selectedUsers = newList;
  399. this.rule.users = newList
  400. },
  401. // 确认选择员工
  402. confirmUserSelection() {
  403. if (this.selectedUsers.length === 0) {
  404. this.$message.warning('请选择员工');
  405. return;
  406. }
  407. const mergedArray = [
  408. ...this.rule.members,
  409. ...this.selectedUsers.filter(item => !this.rule.members.some(a1 => a1.userName === item.userName))
  410. ];
  411. this.rule.members = mergedArray
  412. this.userSelectionDialogVisible = false;
  413. },
  414. // 多选框选中数据
  415. handleSelectionChange(selection) {
  416. this.ids = selection.map((item) => item.id)
  417. this.single = selection.length !== 1
  418. this.multiple = !selection.length
  419. },
  420. // 移除员工
  421. removeMember(member) {
  422. this.$confirm('确定要移除该员工吗?', '提示', {
  423. type: 'warning'
  424. }).then(() => {
  425. this.rule.members = this.rule.members.filter(
  426. m => m.id !== member.id
  427. );
  428. // console.log(member)
  429. delUser(member.id).then((res) => {
  430. // console.log(res)
  431. this.$message.success('用户删除成功!');
  432. this.getList()
  433. })
  434. }).catch(() => {
  435. // 取消操作
  436. });
  437. },
  438. // 取消按钮
  439. cancel() {
  440. this.open = false;
  441. this.applicableRangeFlag = false
  442. // this.reset();
  443. },
  444. // 处理关闭员工对话框
  445. handleCloseUserDialog(done) {
  446. if (this.selectedUsers.length > 0) {
  447. this.$confirm('确定要取消选择吗?', '提示', {
  448. type: 'warning'
  449. }).then(() => {
  450. done();
  451. }).catch(() => {
  452. // 取消关闭
  453. });
  454. } else {
  455. done();
  456. }
  457. },
  458. // 重置表单
  459. resetForm() {
  460. this.attendanceGroup = {
  461. id: null,
  462. name: '',
  463. description: '',
  464. workDays: ['mon', 'tue', 'wed', 'thu', 'fri'],
  465. workStartTime: '09:00',
  466. workEndTime: '18:00',
  467. allowLate: true,
  468. lateRange: 15,
  469. allowEarly: true,
  470. earlyRange: 15,
  471. areaId: null,
  472. checkInType: 'location',
  473. members: [],
  474. areaName: ''
  475. };
  476. this.isEditMode = false;
  477. this.selectedGroupId = null;
  478. },
  479. // 是否允许请假半天
  480. handleLateChange(value) {
  481. console.log(value)
  482. }
  483. }
  484. }
  485. </script>
  486. <style lang="scss" scoped>
  487. .attendance-group-container {
  488. padding: 20px;
  489. }
  490. .page-header {
  491. margin-bottom: 30px;
  492. }
  493. .page-header h1 {
  494. font-size: 24px;
  495. font-weight: 600;
  496. margin-bottom: 10px;
  497. }
  498. .page-header p {
  499. color: #606266;
  500. }
  501. .main-content {
  502. max-width: 1200px;
  503. margin: 0 auto;
  504. }
  505. .group-list-card, .group-form-card {
  506. border-radius: 8px;
  507. box-shadow: 0 2px 12px 0 rgba(0, 0, 0, 0.1);
  508. }
  509. .card-header {
  510. display: flex;
  511. justify-content: space-between;
  512. align-items: center;
  513. }
  514. .search-container {
  515. display: flex;
  516. gap: 10px;
  517. margin-bottom: 20px;
  518. }
  519. .slider-value {
  520. text-align: center;
  521. margin-top: 10px;
  522. color: #606266;
  523. }
  524. /* 表单验证错误提示样式 */
  525. .el-form-item__error {
  526. padding-top: 4px;
  527. }
  528. /* 表格样式优化 */
  529. .el-table {
  530. border-radius: 4px;
  531. }
  532. .el-table th {
  533. background-color: #f5f7fa;
  534. }
  535. /* 按钮样式优化 */
  536. .el-button {
  537. transition: all 0.2s;
  538. }
  539. .el-button:hover {
  540. transform: translateY(-1px);
  541. }
  542. /* 消息提示样式 */
  543. .el-message {
  544. top: 80px;
  545. }
  546. /* 考勤组列表样式 */
  547. .group-list {
  548. max-height: 400px;
  549. overflow-y: auto;
  550. padding: 10px 0;
  551. }
  552. .group-item {
  553. padding: 15px;
  554. margin-bottom: 10px;
  555. border-radius: 4px;
  556. cursor: pointer;
  557. background-color: #fff;
  558. border: 1px solid #ebeef5;
  559. transition: all 0.3s;
  560. }
  561. .group-item:hover {
  562. border-color: #409eff;
  563. background-color: #f5f7fa;
  564. }
  565. .group-item.active {
  566. border-color: #409eff;
  567. background-color: #ecf5ff;
  568. }
  569. .group-name {
  570. font-weight: 500;
  571. margin-bottom: 5px;
  572. color: #303133;
  573. }
  574. .group-desc {
  575. font-size: 13px;
  576. color: #606266;
  577. margin-bottom: 5px;
  578. overflow: hidden;
  579. text-overflow: ellipsis;
  580. white-space: nowrap;
  581. }
  582. .group-meta {
  583. font-size: 12px;
  584. color: #909399;
  585. }
  586. .empty-state {
  587. text-align: center;
  588. padding: 30px 0;
  589. color: #909399;
  590. }
  591. .empty-state i {
  592. font-size: 36px;
  593. margin-bottom: 10px;
  594. display: block;
  595. color: #dcdfe6;
  596. }
  597. /* 响应式布局 */
  598. @media (max-width: 768px) {
  599. .main-content {
  600. flex-direction: column;
  601. }
  602. .group-list-card, .group-form-card {
  603. width: 100%;
  604. }
  605. }
  606. .warn-result table {
  607. width: 100% !important;
  608. }
  609. .warn-result table td a {
  610. display: none;
  611. }
  612. .warn-result table img {
  613. width: 100% !important;
  614. }
  615. .warn-result-message {
  616. .warn-result-text {
  617. font-size: 14px;
  618. color: #303133;
  619. a {
  620. color: #409eff;
  621. text-decoration: underline;
  622. }
  623. }
  624. .warn-result-tips {
  625. font-size: 12px;
  626. color: #999;
  627. margin-top: 10px;
  628. }
  629. }
  630. </style>
  631. <style lang="scss" scoped>
  632. .goods--info {
  633. display: flex;
  634. flex-direction: column;
  635. justify-content: center;
  636. text-align: left;
  637. .el-link {
  638. font-size: 14px;
  639. display: -webkit-box;
  640. -webkit-line-clamp: 2;
  641. line-clamp: 2;
  642. -webkit-box-orient: vertical;
  643. overflow: hidden;
  644. }
  645. em {
  646. font-size: 12px;
  647. color: #999;
  648. font-style: normal;
  649. }
  650. }
  651. .attendance-area-config {
  652. padding: 20px;
  653. font-family: Arial, sans-serif;
  654. max-width: 1200px;
  655. margin: 0 auto;
  656. }
  657. .page-header {
  658. text-align: center;
  659. margin-bottom: 30px;
  660. }
  661. .page-header h1 {
  662. color: #333;
  663. margin-bottom: 10px;
  664. }
  665. .page-header p {
  666. color: #666;
  667. }
  668. .content-wrapper {
  669. display: flex;
  670. gap: 20px;
  671. }
  672. .area-list {
  673. flex: 1;
  674. min-width: 400px;
  675. }
  676. .list-header {
  677. display: flex;
  678. justify-content: space-between;
  679. align-items: center;
  680. margin-bottom: 15px;
  681. }
  682. .list-header h2 {
  683. margin: 0;
  684. color: #333;
  685. }
  686. .btn-add {
  687. background-color: #409eff;
  688. color: white;
  689. border: none;
  690. padding: 8px 12px;
  691. border-radius: 4px;
  692. cursor: pointer;
  693. transition: background-color 0.3s;
  694. }
  695. .btn-add:hover {
  696. background-color: #3a8ee6;
  697. }
  698. .area-table {
  699. border: 1px solid #ddd;
  700. border-radius: 4px;
  701. overflow: hidden;
  702. }
  703. .area-table table {
  704. width: 100%;
  705. border-collapse: collapse;
  706. }
  707. .area-table th,
  708. .area-table td {
  709. padding: 10px;
  710. text-align: left;
  711. border-bottom: 1px solid #eee;
  712. }
  713. .area-table th {
  714. background-color: #f5f7fa;
  715. color: #606266;
  716. font-weight: bold;
  717. }
  718. .area-table tr:last-child td {
  719. border-bottom: none;
  720. }
  721. .area-table tr:hover {
  722. background-color: #fafafa;
  723. }
  724. .status-enabled {
  725. display: inline-block;
  726. padding: 2px 6px;
  727. background-color: #e6f7ff;
  728. color: #1890ff;
  729. border-radius: 3px;
  730. font-size: 12px;
  731. }
  732. .status-disabled {
  733. display: inline-block;
  734. padding: 2px 6px;
  735. background-color: #f5f5f5;
  736. color: #999;
  737. border-radius: 3px;
  738. font-size: 12px;
  739. }
  740. .btn-edit,
  741. .btn-status,
  742. .btn-delete {
  743. padding: 5px 10px;
  744. margin-right: 5px;
  745. border: none;
  746. border-radius: 4px;
  747. cursor: pointer;
  748. transition: background-color 0.3s;
  749. font-size: 12px;
  750. }
  751. .btn-edit {
  752. background-color: #e6f7ff;
  753. color: #1890ff;
  754. }
  755. .btn-edit:hover {
  756. background-color: #d6efff;
  757. }
  758. .btn-status {
  759. background-color: #f6ffed;
  760. color: #52c41a;
  761. }
  762. .btn-status:hover {
  763. background-color: #e8ffd9;
  764. }
  765. .btn-status:disabled {
  766. background-color: #f5f5f5;
  767. color: #999;
  768. cursor: not-allowed;
  769. }
  770. .btn-delete {
  771. background-color: #fff2f0;
  772. color: #ff4d4f;
  773. }
  774. .btn-delete:hover {
  775. background-color: #ffe5e3;
  776. }
  777. .btn-delete:disabled {
  778. background-color: #f5f5f5;
  779. color: #999;
  780. cursor: not-allowed;
  781. }
  782. .empty-state {
  783. text-align: center;
  784. padding: 50px 20px;
  785. color: #999;
  786. }
  787. .empty-state i {
  788. font-size: 40px;
  789. margin-bottom: 10px;
  790. display: block;
  791. }
  792. .map-section {
  793. flex: 1;
  794. }
  795. .map-section h2 {
  796. margin-top: 0;
  797. color: #333;
  798. }
  799. .map-controls {
  800. display: flex;
  801. flex-wrap: wrap;
  802. gap: 15px;
  803. margin-bottom: 15px;
  804. }
  805. .control-group {
  806. display: flex;
  807. align-items: center;
  808. gap: 5px;
  809. min-width: 220px;
  810. }
  811. .control-group label {
  812. font-weight: bold;
  813. min-width: 80px;
  814. }
  815. .control-group input {
  816. flex: 1;
  817. padding: 6px 10px;
  818. border: 1px solid #ddd;
  819. border-radius: 4px;
  820. }
  821. .radius-slider {
  822. width: 100%;
  823. display: flex;
  824. align-items: center;
  825. gap: 10px;
  826. }
  827. .radius-slider input[type="range"] {
  828. flex: 1;
  829. }
  830. .map {
  831. border: 1px solid #ddd;
  832. border-radius: 4px;
  833. margin-bottom: 15px;
  834. }
  835. .map-actions {
  836. display: flex;
  837. gap: 10px;
  838. }
  839. .btn-clear,
  840. .btn-save {
  841. padding: 8px 15px;
  842. border: none;
  843. border-radius: 4px;
  844. cursor: pointer;
  845. transition: background-color 0.3s;
  846. display: flex;
  847. align-items: center;
  848. gap: 5px;
  849. }
  850. .btn-clear {
  851. background-color: #f5f5f5;
  852. color: #666;
  853. }
  854. .btn-clear:hover {
  855. background-color: #eee;
  856. }
  857. .btn-save {
  858. background-color: #409eff;
  859. color: white;
  860. }
  861. .btn-save:hover {
  862. background-color: #3a8ee6;
  863. }
  864. .btn-save:disabled {
  865. background-color: #e6e6e6;
  866. color: #999;
  867. cursor: not-allowed;
  868. }
  869. .modal-overlay {
  870. position: fixed;
  871. top: 0;
  872. left: 0;
  873. width: 100%;
  874. height: 100%;
  875. background-color: rgba(0, 0, 0, 0.5);
  876. display: flex;
  877. justify-content: center;
  878. align-items: center;
  879. z-index: 1000;
  880. }
  881. .modal-content {
  882. background-color: white;
  883. border-radius: 4px;
  884. padding: 20px;
  885. width: 300px;
  886. box-shadow: 0 2px 10px rgba(0, 0, 0, 0.1);
  887. }
  888. .modal-content h3 {
  889. margin-top: 0;
  890. color: #333;
  891. }
  892. .modal-actions {
  893. display: flex;
  894. justify-content: flex-end;
  895. gap: 10px;
  896. margin-top: 20px;
  897. }
  898. .btn-cancel,
  899. .btn-confirm {
  900. padding: 8px 15px;
  901. border: none;
  902. border-radius: 4px;
  903. cursor: pointer;
  904. transition: background-color 0.3s;
  905. }
  906. .btn-cancel {
  907. background-color: #f5f5f5;
  908. color: #666;
  909. }
  910. .btn-cancel:hover {
  911. background-color: #eee;
  912. }
  913. .btn-confirm {
  914. background-color: #409eff;
  915. color: white;
  916. }
  917. .btn-confirm:hover {
  918. background-color: #3a8ee6;
  919. }
  920. /* 响应式设计 */
  921. @media (max-width: 900px) {
  922. .content-wrapper {
  923. flex-direction: column;
  924. }
  925. .area-list,
  926. .map-section {
  927. min-width: auto;
  928. }
  929. }
  930. @media (max-width: 500px) {
  931. .control-group {
  932. min-width: 100%;
  933. }
  934. .area-table th,
  935. .area-table td {
  936. padding: 8px 5px;
  937. font-size: 14px;
  938. }
  939. .btn-edit,
  940. .btn-status,
  941. .btn-delete {
  942. padding: 4px 6px;
  943. margin-right: 2px;
  944. }
  945. }
  946. </style>