综合办公系统
Ви не можете вибрати більше 25 тем Теми мають розпочинатися з літери або цифри, можуть містити дефіси (-) і не повинні перевищувати 35 символів.

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929
  1. <!--
  2. * @Author: ysh
  3. * @Date: 2025-06-10 09:34:55
  4. * @LastEditors: Please set LastEditors
  5. * @LastEditTime: 2025-06-12 14:51:18
  6. -->
  7. <template>
  8. <view>
  9. <scroll-view :scroll-top="scrollTop" scroll-y="true" class="scroll-Y" @scrolltoupper="upper" @scrolltolower="lower"
  10. @scroll="scroll" :refresher-enabled="true" :refresher-triggered="isRefreshing" @refresherrefresh="onRefresh"
  11. :lower-threshold="50" :upper-threshold="50">
  12. <view class="content-wrapper">
  13. <!-- 搜索栏 -->
  14. <view class="search-bar">
  15. <view class="search-input-wrapper">
  16. <uni-icons type="search" size="16" color="#999"></uni-icons>
  17. <input class="search-input" v-model="queryParams.projectNumber" placeholder="请输入项目编号搜索"
  18. @confirm="handleSearch" />
  19. <uni-icons v-if="queryParams.projectNumber" type="clear" size="16" color="#999"
  20. @click="clearSearch"></uni-icons>
  21. </view>
  22. </view>
  23. <template v-if="logList.length > 0">
  24. <view class="project-card" v-for="(item, index) in logList" :key="index">
  25. <view class="project-card-item">
  26. <view class="project-card-item-header">
  27. <view class="project-info">
  28. <text class="project-number">{{ item.project ? item.project.projectNumber : '无项目' }}</text>
  29. <text class="project-name">{{ item.project ? item.project.projectName : '无项目' }}</text>
  30. </view>
  31. <view class="action-buttons">
  32. <button class="action-btn edit" v-if="isOwnRecord(item)" @click="handleEdit(item)">
  33. <uni-icons type="compose" size="16" color="#007AFF"></uni-icons>
  34. </button>
  35. <button class="action-btn delete" v-if="isOwnRecord(item)" @click="handleDelete(item)">
  36. <uni-icons type="trash" size="16" color="#FF3B30"></uni-icons>
  37. </button>
  38. </view>
  39. </view>
  40. <view class="project-card-item-content">
  41. <view class="info-row">
  42. <text class="info-label">设备名称:</text>
  43. <text class="info-value" v-if="item.deviceId">{{ item.device ? item.device.name : '' }}-{{ item.device
  44. ? item.device.brand : '' }}({{
  45. item.device ? item.device.code : '' }})</text>
  46. <text class="info-value" v-else>暂无设备</text>
  47. </view>
  48. <view class="info-row">
  49. <text class="info-label">设备类型:</text>
  50. <text class="info-value">{{ item.usageType }}</text>
  51. </view>
  52. <view class="info-row">
  53. <text class="info-label">使用日期:</text>
  54. <text class="info-value">{{ item.useDate }}</text>
  55. </view>
  56. <view class="info-row">
  57. <text class="info-label">记录员:</text>
  58. <text class="info-value">{{ item.user.nickName }}</text>
  59. </view>
  60. <view class="info-row">
  61. <text class="info-label">点号:</text>
  62. <text class="info-value">{{ item.position }}</text>
  63. </view>
  64. <view class="info-row">
  65. <text class="info-label">高值类型:</text>
  66. <text class="info-value">{{ item.heightType }}</text>
  67. </view>
  68. <view class="info-row">
  69. <text class="info-label">高值:</text>
  70. <text class="info-value">{{ item.height }}m</text>
  71. </view>
  72. <view class="info-row">
  73. <text class="info-label">天气:</text>
  74. <text class="info-value">{{ item.weather }}</text>
  75. </view>
  76. <view class="info-row">
  77. <text class="info-label">干温:</text>
  78. <text class="info-value">{{ item.dryTemperature }}°C</text>
  79. </view>
  80. <view class="info-row">
  81. <text class="info-label">湿温:</text>
  82. <text class="info-value">{{ item.wetTemperature }}°C</text>
  83. </view>
  84. <view class="info-row">
  85. <text class="info-label">气压:</text>
  86. <text class="info-value">{{ item.airPressure }}hPa</text>
  87. </view>
  88. <view class="info-row">
  89. <text class="info-label">开机时间:</text>
  90. <text class="info-value">{{ formatDateTime(item.powerOn) }}</text>
  91. </view>
  92. <view class="info-row">
  93. <text class="info-label">关机时间:</text>
  94. <text class="info-value">{{ formatDateTime(item.powerOff) }}</text>
  95. </view>
  96. </view>
  97. </view>
  98. </view>
  99. <view class="loading-more" v-if="hasMore">
  100. <text class="loading-text">加载中...</text>
  101. </view>
  102. <view class="no-more" v-else>
  103. <text class="no-more-text">没有更多数据了</text>
  104. </view>
  105. </template>
  106. <view v-else class="empty-state">
  107. <image src="/static/images/empty.png" mode="aspectFit" class="empty-image"></image>
  108. <text class="empty-text">暂无数据</text>
  109. </view>
  110. </view>
  111. </scroll-view>
  112. <!-- 悬浮按钮 -->
  113. <view class="fab-button" @click="handleAdd">
  114. <uni-icons type="plusempty" size="24" color="#fff"></uni-icons>
  115. </view>
  116. <!-- 新增记录弹窗 -->
  117. <uni-popup ref="addPopup" type="center">
  118. <view class="popup-content">
  119. <view class="popup-header">
  120. <text class="title">{{ isEdit ? '修改记录' : '新增记录' }}</text>
  121. <uni-icons type="close" size="20" @click="closePopup"></uni-icons>
  122. </view>
  123. <view class="popup-body">
  124. <view class="form-item">
  125. <text class="label">项目选择</text>
  126. <view class="project-picker" @click="showProjectPicker">
  127. <text v-if="selectedProject">{{ selectedProject.projectName }}</text>
  128. <text v-else class="placeholder">请选择项目</text>
  129. </view>
  130. </view>
  131. <view class="form-item">
  132. <text class="label">设备选择</text>
  133. <view class="project-picker" @click="showDevicePicker">
  134. <text v-if="selectDevice && selectDevice.code">{{ selectDevice.name }}-{{ selectDevice.brand }}({{
  135. selectDevice.code
  136. }})</text>
  137. <text v-else class="placeholder">请选择设备</text>
  138. </view>
  139. </view>
  140. <view class="form-item">
  141. <text class="label">设备类型</text>
  142. <uni-data-select v-model="formData.usageType" :localdata="useTypeOptions" placeholder="请选择设备类型"
  143. class="weather-select" @change="handleUseTypeChange" />
  144. </view>
  145. <view class="form-item">
  146. <text class="label">使用日期</text>
  147. <!-- <uni-datetime-picker v-model="formData.useDate" type="date" /> -->
  148. <uv-calendar ref="calendar" mode="single" @confirm="confirmUseDate"></uv-calendar>
  149. <view class="project-picker" @click="$refs.calendar.open()">
  150. <text v-if="formData.useDate">{{ formData.useDate }}</text>
  151. <text v-else class="placeholder">请选择日期</text>
  152. </view>
  153. </view>
  154. <view class="form-item">
  155. <text class="label">点号</text>
  156. <input v-model="formData.position" placeholder="请输入点号" />
  157. </view>
  158. <view class="form-item">
  159. <text class="label">高值类型</text>
  160. <uni-data-select v-model="formData.heightType" :localdata="highTypeOptions" placeholder="请选择高值类型"
  161. class="weather-select" @change="handleHighTypeChange" />
  162. </view>
  163. <view class="form-item">
  164. <text class="label">高值(m)</text>
  165. <input v-model="formData.height" type="number" placeholder="请输入高值" />
  166. </view>
  167. <view class="form-item">
  168. <text class="label">天气</text>
  169. <uni-data-select v-model="formData.weather" :localdata="weatherOptions" placeholder="请选择天气"
  170. class="weather-select" />
  171. </view>
  172. <view class="form-item">
  173. <text class="label">干温 (°C)</text>
  174. <input v-model="formData.dryTemperature" type="number" placeholder="请输入干温" />
  175. </view>
  176. <view class="form-item">
  177. <text class="label">湿温 (°C)</text>
  178. <input v-model="formData.wetTemperature" type="number" placeholder="请输入湿温" />
  179. </view>
  180. <view class="form-item">
  181. <text class="label">气压 (hPa)</text>
  182. <input v-model="formData.airPressure" type="number" placeholder="请输入气压" />
  183. </view>
  184. <view class="form-item" v-if="formData.usageType !== '全站仪'">
  185. <text class="label">开机时间</text>
  186. <view class="datetime-picker" @click="openPowerOnPicker">
  187. <view style="flex: 8;" v-if="formData.powerOn">{{ formatDateTime(formData.powerOn) }}</view>
  188. <view style="flex: 1;text-align: right;" v-if="formData.powerOn" @click="formData.powerOn = ''">
  189. <uv-icon name="close-circle-fill" size="16"></uv-icon>
  190. </view>
  191. <text v-else class="placeholder">请选择开机时间</text>
  192. </view>
  193. </view>
  194. <view class="form-item" v-if="formData.usageType !== '全站仪'">
  195. <text class="label">关机时间</text>
  196. <view class="datetime-picker" @click="openPowerOffPicker">
  197. <view style="flex: 8;" v-if="formData.powerOff">{{ formatDateTime(formData.powerOff) }}</view>
  198. <view style="flex: 1;text-align: right;" v-if="formData.powerOff" @click="formData.powerOff = ''">
  199. <uv-icon name="close-circle-fill" size="16"></uv-icon>
  200. </view>
  201. <text v-else class="placeholder">请选择关机时间</text>
  202. </view>
  203. </view>
  204. </view>
  205. <view class="popup-footer">
  206. <button class="btn cancel" @click="closePopup">取消</button>
  207. <button class="btn confirm" @click="submitForm">确定</button>
  208. </view>
  209. </view>
  210. </uni-popup>
  211. <!-- 项目选择器 -->
  212. <project-picker :visible.sync="showPicker" :selected.sync="selectedProject" @confirm="handleProjectSelect" />
  213. <!-- 设备选择器 -->
  214. <device-picker :visible.sync="openDevice" :selected.sync="selectDevice" :multiple="false"
  215. @confirm="handleDeviceSelect"></device-picker>
  216. <!-- 时间选择器 -->
  217. <uv-datetime-picker ref="powerOnPicker" v-model="formData.powerOn" mode="datetime"
  218. @confirm="handlePowerOnConfirm"></uv-datetime-picker>
  219. <uv-datetime-picker ref="powerOffPicker" v-model="formData.powerOff" mode="datetime"
  220. @confirm="handlePowerOffConfirm"></uv-datetime-picker>
  221. </view>
  222. </template>
  223. <script>
  224. import { listDeviceLog, getDeviceLog, addDeviceLog, updateDeviceLog, delDeviceLog } from '@/api/oa/device/deviceLog';
  225. import { listProject } from '@/api/oa/project/project';
  226. import ProjectPicker from '@/pages/components/ProjectPicker.vue';
  227. import DevicePicker from '@/pages/components/DevicePicker.vue';
  228. import { parseTime } from '@/utils/common';
  229. export default {
  230. components: {
  231. ProjectPicker,
  232. DevicePicker
  233. },
  234. data() {
  235. return {
  236. logList: [],
  237. scrollTop: 0,
  238. queryParams: {
  239. pageNum: 1,
  240. pageSize: 10,
  241. userId: null,
  242. projectNumber: '',
  243. useDate: ''
  244. },
  245. showPicker: false,
  246. selectedProject: null,
  247. openDevice: false,
  248. selectDevice: {},
  249. weatherOptions: [
  250. { text: '晴', value: '晴' },
  251. { text: '阴', value: '阴' },
  252. { text: '多云', value: '多云' },
  253. { text: '雨', value: '雨' },
  254. { text: '雪', value: '雪' }
  255. ],
  256. highTypeOptions: [],
  257. useTypeOptions: [
  258. { text: '全站仪', value: '全站仪' },
  259. { text: 'GNSS基站', value: 'GNSS基站' },
  260. { text: 'GNSS静态', value: 'GNSS静态' }
  261. ],
  262. formData: {
  263. useDate: '',
  264. weather: '',
  265. position: '',
  266. dryTemperature: '',
  267. wetTemperature: '',
  268. airPressure: '',
  269. heightType: '',
  270. height: '',
  271. powerOn: '',
  272. powerOff: '',
  273. usageType: ''
  274. },
  275. isEdit: false,
  276. currentLogId: null,
  277. hasMore: true,
  278. loading: false,
  279. isRefreshing: false
  280. }
  281. },
  282. created() {
  283. this.getList()
  284. },
  285. methods: {
  286. async getList() {
  287. if (this.loading) return
  288. this.loading = true
  289. try {
  290. if (this.$store.getters.roles.includes('leader') || this.$store.getters.roles.includes('dept')) {
  291. this.queryParams.userId = null
  292. } else {
  293. this.queryParams.userId = this.$store.getters.userId
  294. }
  295. const res = await listDeviceLog(this.queryParams)
  296. if (this.queryParams.pageNum === 1) {
  297. this.logList = res.rows
  298. } else {
  299. this.logList = [...this.logList, ...res.rows]
  300. }
  301. this.hasMore = res.rows.length === this.queryParams.pageSize
  302. } catch (error) {
  303. uni.showToast({
  304. title: '加载失败',
  305. icon: 'error'
  306. })
  307. } finally {
  308. this.loading = false
  309. }
  310. },
  311. async onRefresh() {
  312. this.isRefreshing = true
  313. this.queryParams.pageNum = 1
  314. this.hasMore = true
  315. await this.getList()
  316. this.isRefreshing = false
  317. },
  318. upper() {
  319. // 下拉刷新
  320. this.onRefresh()
  321. },
  322. lower() {
  323. // 上拉加载更多
  324. if (this.hasMore && !this.loading) {
  325. this.queryParams.pageNum++
  326. this.getList()
  327. }
  328. },
  329. scroll(e) {
  330. // 可以在这里添加滚动相关的逻辑
  331. },
  332. handleAdd() {
  333. this.formData.useDate = parseTime(new Date(), '{y}-{m}-{d}');
  334. this.$refs.addPopup.open()
  335. },
  336. closePopup() {
  337. this.$refs.addPopup.close()
  338. this.resetForm()
  339. },
  340. showProjectPicker() {
  341. this.showPicker = true
  342. },
  343. showDevicePicker() {
  344. this.openDevice = true
  345. },
  346. handleProjectSelect(project) {
  347. this.selectedProject = project
  348. },
  349. handleDeviceSelect(device) {
  350. this.selectDevice = device
  351. },
  352. openPowerOnPicker() {
  353. this.$refs.powerOnPicker.open()
  354. },
  355. openPowerOffPicker() {
  356. this.$refs.powerOffPicker.open()
  357. },
  358. handlePowerOnConfirm(e) {
  359. this.formData.powerOn = e.value
  360. },
  361. handlePowerOffConfirm(e) {
  362. this.formData.powerOff = e.value
  363. },
  364. confirmUseDate(e) {
  365. this.formData.useDate = parseTime(e[0], '{y}-{m}-{d}')
  366. },
  367. formatDateTime(timestamp) {
  368. if (!timestamp) return ''
  369. const date = new Date(timestamp)
  370. const year = date.getFullYear()
  371. const month = String(date.getMonth() + 1).padStart(2, '0')
  372. const day = String(date.getDate()).padStart(2, '0')
  373. const hours = String(date.getHours()).padStart(2, '0')
  374. const minutes = String(date.getMinutes()).padStart(2, '0')
  375. return `${year}-${month}-${day} ${hours}:${minutes}`
  376. },
  377. resetForm() {
  378. this.isEdit = false
  379. this.currentLogId = null
  380. this.selectedProject = null
  381. this.formData = {
  382. useDate: '',
  383. weather: '',
  384. position: '',
  385. dryTemperature: '',
  386. wetTemperature: '',
  387. airPressure: '',
  388. heightType: '',
  389. height: '',
  390. powerOn: '',
  391. powerOff: '',
  392. usageType: ''
  393. }
  394. },
  395. async submitForm() {
  396. if (!this.selectDevice) {
  397. uni.showToast({
  398. title: '请选择设备',
  399. icon: 'none'
  400. })
  401. return
  402. }
  403. const params = {
  404. ...this.formData,
  405. projectId: this.selectedProject ? this.selectedProject.projectId : null,
  406. deviceId: this.selectDevice.deviceId,
  407. userId: this.$store.getters.userId,
  408. powerOn: this.formData.powerOn,
  409. powerOff: this.formData.powerOff
  410. }
  411. try {
  412. if (this.isEdit) {
  413. await updateDeviceLog({
  414. ...params,
  415. logId: this.currentLogId
  416. })
  417. uni.showToast({
  418. title: '修改成功',
  419. icon: 'success'
  420. })
  421. } else {
  422. await addDeviceLog(params)
  423. uni.showToast({
  424. title: '添加成功',
  425. icon: 'success'
  426. })
  427. }
  428. this.closePopup()
  429. this.getList()
  430. } catch (error) {
  431. uni.showToast({
  432. title: this.isEdit ? '修改失败' : '添加失败',
  433. icon: 'error'
  434. })
  435. }
  436. },
  437. handleEdit(item) {
  438. this.isEdit = true
  439. this.currentLogId = item.logId
  440. this.selectedProject = item.project
  441. this.selectDevice = item.device ? item.device : {}
  442. this.formData = {
  443. useDate: item.useDate,
  444. weather: item.weather,
  445. position: item.position,
  446. dryTemperature: item.dryTemperature,
  447. wetTemperature: item.wetTemperature,
  448. airPressure: item.airPressure,
  449. heightType: item.heightType,
  450. height: item.height,
  451. powerOn: item.powerOn,
  452. powerOff: item.powerOff,
  453. usageType: item.usageType
  454. }
  455. if (item.usageType === '全站仪') {
  456. this.highTypeOptions = [
  457. { text: '仪器高', value: '仪器高' },
  458. { text: '棱镜高', value: '棱镜高' }
  459. ]
  460. } else if (item.usageType === 'GNSS基站' || item.usageType === 'GNSS静态') {
  461. this.highTypeOptions = [
  462. { text: '斜高', value: '斜高' },
  463. { text: '直高', value: '直高' },
  464. { text: '杆高', value: '杆高' },
  465. { text: '天线高', value: '天线高' }
  466. ]
  467. }
  468. this.$refs.addPopup.open()
  469. },
  470. async handleDelete(item) {
  471. try {
  472. const [err, res] = await uni.showModal({
  473. title: '确认删除',
  474. content: '确定要删除这条记录吗?',
  475. confirmColor: '#FF3B30'
  476. })
  477. if (err || !res.confirm) {
  478. return
  479. }
  480. await delDeviceLog(item.logId)
  481. uni.showToast({
  482. title: '删除成功',
  483. icon: 'success'
  484. })
  485. this.getList()
  486. } catch (error) {
  487. uni.showToast({
  488. title: '删除失败',
  489. icon: 'error'
  490. })
  491. }
  492. },
  493. handleHighTypeChange(value) {
  494. this.formData.heightType = value
  495. },
  496. handleUseTypeChange(value) {
  497. this.formData.usageType = value
  498. if (value === '全站仪') {
  499. this.highTypeOptions = [
  500. { text: '仪器高', value: '仪器高' },
  501. { text: '棱镜高', value: '棱镜高' }
  502. ]
  503. } else if (value === 'GNSS基站' || value === 'GNSS静态') {
  504. this.highTypeOptions = [
  505. { text: '斜高', value: '斜高' },
  506. { text: '直高', value: '直高' },
  507. { text: '杆高', value: '杆高' },
  508. { text: '天线高', value: '天线高' }
  509. ]
  510. }
  511. this.formData.heightType = ''
  512. },
  513. async handleSearch() {
  514. this.queryParams.pageNum = 1
  515. const res = await listProject(this.queryParams)
  516. let projectList = res.rows;
  517. if (projectList.length == 1) {
  518. this.queryParams.projectId = projectList[0].projectId
  519. } else {
  520. this.queryParams.projectId = null
  521. }
  522. this.getList()
  523. },
  524. clearSearch() {
  525. this.queryParams.projectNumber = ''
  526. this.queryParams.projectId = null
  527. this.getList()
  528. },
  529. isOwnRecord(item) {
  530. return item.user.userId === this.$store.getters.userId
  531. }
  532. }
  533. }
  534. </script>
  535. <style lang="scss" scoped>
  536. .scroll-Y {
  537. height: 100vh;
  538. background: #f8f8f8;
  539. box-sizing: border-box;
  540. position: relative;
  541. padding-bottom: 120rpx;
  542. }
  543. .content-wrapper {
  544. padding: 20rpx;
  545. min-height: 100%;
  546. }
  547. .fab-button {
  548. position: fixed;
  549. right: 30rpx;
  550. bottom: 50rpx;
  551. width: 100rpx;
  552. height: 100rpx;
  553. background: #007AFF;
  554. border-radius: 50%;
  555. display: flex;
  556. align-items: center;
  557. justify-content: center;
  558. box-shadow: 0 4rpx 16rpx rgba(0, 122, 255, 0.3);
  559. z-index: 99;
  560. transition: all 0.3s;
  561. &:active {
  562. transform: scale(0.95);
  563. background: #0062cc;
  564. }
  565. }
  566. .project-card {
  567. margin-bottom: 20rpx;
  568. background: #fff;
  569. border-radius: 12rpx;
  570. box-shadow: 0 2rpx 12rpx rgba(0, 0, 0, 0.1);
  571. &:last-child {
  572. margin-bottom: 0;
  573. }
  574. &-item {
  575. padding: 20rpx;
  576. &-header {
  577. display: flex;
  578. justify-content: space-between;
  579. align-items: center;
  580. margin-bottom: 20rpx;
  581. padding-bottom: 20rpx;
  582. border-bottom: 2rpx solid #f5f5f5;
  583. .project-info {
  584. display: flex;
  585. align-items: center;
  586. gap: 20rpx;
  587. .project-number {
  588. font-size: 28rpx;
  589. color: #666;
  590. background: #f5f5f5;
  591. padding: 4rpx 16rpx;
  592. border-radius: 8rpx;
  593. }
  594. .project-name {
  595. font-size: 32rpx;
  596. color: #333;
  597. font-weight: bold;
  598. }
  599. }
  600. .action-buttons {
  601. display: flex;
  602. gap: 16rpx;
  603. .action-btn {
  604. width: 64rpx;
  605. height: 64rpx;
  606. display: flex;
  607. align-items: center;
  608. justify-content: center;
  609. background: #f8f8f8;
  610. border: none;
  611. border-radius: 8rpx;
  612. padding: 0;
  613. transition: all 0.3s;
  614. &:active {
  615. transform: scale(0.95);
  616. }
  617. &.edit {
  618. &:active {
  619. background: #e6f2ff;
  620. }
  621. }
  622. &.delete {
  623. &:active {
  624. background: #ffe6e6;
  625. }
  626. }
  627. }
  628. }
  629. }
  630. &-content {
  631. display: flex;
  632. flex-direction: column;
  633. gap: 12rpx;
  634. .info-row {
  635. display: flex;
  636. align-items: center;
  637. font-size: 26rpx;
  638. line-height: 1.5;
  639. .info-label {
  640. color: #666;
  641. width: 140rpx;
  642. flex-shrink: 0;
  643. }
  644. .info-value {
  645. color: #333;
  646. flex: 1;
  647. }
  648. }
  649. }
  650. }
  651. }
  652. .empty-state {
  653. display: flex;
  654. flex-direction: column;
  655. align-items: center;
  656. justify-content: center;
  657. padding: 120rpx 0;
  658. .empty-image {
  659. width: 240rpx;
  660. height: 240rpx;
  661. margin-bottom: 20rpx;
  662. }
  663. .empty-text {
  664. font-size: 28rpx;
  665. color: #999;
  666. }
  667. }
  668. .popup-content {
  669. background: #fff;
  670. border-radius: 24rpx;
  671. width: 680rpx;
  672. max-height: 75vh;
  673. .popup-header {
  674. display: flex;
  675. justify-content: space-between;
  676. align-items: center;
  677. padding: 30rpx;
  678. background: #f8f8f8;
  679. .title {
  680. font-size: 34rpx;
  681. font-weight: 600;
  682. color: #333;
  683. }
  684. }
  685. .popup-body {
  686. padding: 30rpx;
  687. max-height: 60vh;
  688. overflow-y: auto;
  689. .form-item {
  690. margin-bottom: 30rpx;
  691. .label {
  692. display: block;
  693. font-size: 28rpx;
  694. color: #333;
  695. margin-bottom: 16rpx;
  696. font-weight: 500;
  697. }
  698. input {
  699. width: 100%;
  700. height: 88rpx;
  701. background: #f8f8f8;
  702. border: 2rpx solid #eee;
  703. border-radius: 12rpx;
  704. padding: 0 24rpx;
  705. font-size: 28rpx;
  706. color: #333;
  707. transition: all 0.3s;
  708. &:focus {
  709. border-color: #007AFF;
  710. background: #fff;
  711. }
  712. &::placeholder {
  713. color: #999;
  714. }
  715. }
  716. .project-picker {
  717. width: 100%;
  718. height: 88rpx;
  719. background: #f8f8f8;
  720. border: 2rpx solid #eee;
  721. border-radius: 12rpx;
  722. padding: 0 24rpx;
  723. display: flex;
  724. align-items: center;
  725. transition: all 0.3s;
  726. &:active {
  727. background: #f0f0f0;
  728. }
  729. .placeholder {
  730. color: #999;
  731. font-size: 28rpx;
  732. }
  733. }
  734. .datetime-picker {
  735. width: 100%;
  736. height: 88rpx;
  737. background: #f8f8f8;
  738. border: 2rpx solid #eee;
  739. border-radius: 12rpx;
  740. padding: 0 24rpx;
  741. display: flex;
  742. align-items: center;
  743. transition: all 0.3s;
  744. &:active {
  745. background: #f0f0f0;
  746. }
  747. .placeholder {
  748. color: #999;
  749. font-size: 28rpx;
  750. }
  751. }
  752. }
  753. }
  754. .popup-footer {
  755. display: flex;
  756. gap: 24rpx;
  757. padding: 30rpx;
  758. background: #f8f8f8;
  759. border-top: 2rpx solid #eee;
  760. .btn {
  761. flex: 1;
  762. height: 88rpx;
  763. line-height: 88rpx;
  764. text-align: center;
  765. border-radius: 12rpx;
  766. font-size: 30rpx;
  767. font-weight: 500;
  768. transition: all 0.3s;
  769. &.cancel {
  770. background: #f0f0f0;
  771. color: #666;
  772. &:active {
  773. background: #e0e0e0;
  774. }
  775. }
  776. &.confirm {
  777. background: #007AFF;
  778. color: #fff;
  779. &:active {
  780. background: #0062cc;
  781. }
  782. }
  783. }
  784. }
  785. }
  786. .weather-select {
  787. :deep(.uni-data-select) {
  788. .uni-select {
  789. height: 88rpx;
  790. background: #f8f8f8;
  791. border: 2rpx solid #eee;
  792. border-radius: 12rpx;
  793. .uni-select__input-box {
  794. height: 88rpx;
  795. line-height: 88rpx;
  796. padding: 0 24rpx;
  797. }
  798. .uni-select__input-text {
  799. font-size: 28rpx;
  800. color: #333;
  801. }
  802. .uni-select__input-placeholder {
  803. color: #999;
  804. }
  805. }
  806. }
  807. }
  808. :deep(.uni-date) {
  809. .uni-date__icon-clear {
  810. display: none;
  811. }
  812. .uni-date-editor {
  813. height: 88rpx;
  814. background: #f8f8f8;
  815. border: 2rpx solid #eee;
  816. border-radius: 12rpx;
  817. .uni-date__input {
  818. height: 88rpx;
  819. line-height: 88rpx;
  820. font-size: 28rpx;
  821. color: #333;
  822. }
  823. }
  824. }
  825. .loading-more,
  826. .no-more {
  827. text-align: center;
  828. padding: 20rpx 0;
  829. margin-bottom: 120rpx;
  830. .loading-text,
  831. .no-more-text {
  832. font-size: 24rpx;
  833. color: #999;
  834. }
  835. }
  836. .search-bar {
  837. padding: 20rpx;
  838. background: #fff;
  839. margin-bottom: 20rpx;
  840. border-radius: 12rpx;
  841. box-shadow: 0 2rpx 12rpx rgba(0, 0, 0, 0.1);
  842. .search-input-wrapper {
  843. display: flex;
  844. align-items: center;
  845. background: #f8f8f8;
  846. border-radius: 8rpx;
  847. padding: 0 20rpx;
  848. height: 72rpx;
  849. .search-input {
  850. flex: 1;
  851. height: 72rpx;
  852. margin: 0 20rpx;
  853. font-size: 28rpx;
  854. color: #333;
  855. &::placeholder {
  856. color: #999;
  857. }
  858. }
  859. }
  860. }
  861. </style>