index.vue 25 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048
  1. <template>
  2. <!-- 访客申请 -->
  3. <view class="container">
  4. <!-- 导航栏 -->
  5. <custom-navbar title="访客申请" :showBack="true"></custom-navbar>
  6. <!-- 表单内容 -->
  7. <view class="form-container">
  8. <!-- 第一块:对接人信息 -->
  9. <view class="section">
  10. <view class="section-title">
  11. <image class="title-icon" src="/static/images/person.png" mode="aspectFit"></image>
  12. 对接人信息
  13. </view>
  14. <view class="mar-b-16" >
  15. <text class="label" >所属部门:</text>
  16. <view class="select-wrapper">
  17. <!-- 调试信息 -->
  18. <uni-data-select v-model="formData.departmentId" :localdata="departmentOptions"
  19. placeholder="请选择所属部门" @change="onDepartmentSelectChange" :clear="false">
  20. </uni-data-select>
  21. </view>
  22. </view>
  23. <view class="form-item1">
  24. <text class="label">员工姓名:</text>
  25. <view class="select-wrapper">
  26. <uni-data-select v-model="formData.employeeId" :localdata="employeeOptions" placeholder="请选择员工"
  27. @change="onEmployeeSelectChange" :clear="false">
  28. </uni-data-select>
  29. </view>
  30. </view>
  31. </view>
  32. <!-- 第二块:访问信息 -->
  33. <view class="section">
  34. <view class="section-title">
  35. <image class="title-icon" src="/static/images/calendar.png" mode="aspectFit"></image>
  36. 访问信息
  37. </view>
  38. <view class="form-item">
  39. <text class="label">访问事由</text>
  40. <input class="input" v-model="formData.visitReason" placeholder="请输入访问事由"
  41. placeholder-style="color: #c0c4cc" />
  42. </view>
  43. <view class="form-item">
  44. <text class="label">到访时间</text>
  45. <uni-datetime-picker type="datetime" v-model="formData.visitTime" @change="onVisitTimeChange"
  46. :clear-icon="false" placeholder="请选择到访时间" format="YYYY-MM-DD HH:mm" :hide-second="true">
  47. <view class="input-wrapper">
  48. <text class="placeholder" v-if="!formData.visitTime">请选择到访时间</text>
  49. <text v-else>{{ formData.visitTime }}</text>
  50. <uni-icons type="calendar" size="16" color="#c0c4cc"></uni-icons>
  51. </view>
  52. </uni-datetime-picker>
  53. </view>
  54. <view class="form-item">
  55. <text class="label">访客姓名</text>
  56. <input class="input" v-model="formData.visitorName" placeholder="请输入访客姓名"
  57. placeholder-style="color: #c0c4cc" />
  58. </view>
  59. <view class="form-item">
  60. <text class="label">访客单位</text>
  61. <input class="input" v-model="formData.visitorCompany" placeholder="请输入访客单位"
  62. placeholder-style="color: #c0c4cc" />
  63. </view>
  64. <view class="form-item">
  65. <text class="label">手机号</text>
  66. <input class="input" v-model="formData.visitorPhone" placeholder="请输入手机号"
  67. placeholder-style="color: #c0c4cc" type="number" />
  68. </view>
  69. </view>
  70. <!-- 第三块:随行人员 -->
  71. <view class="section">
  72. <view class="section-title">随行人员</view>
  73. <view class="accompany-list">
  74. <view class="accompany-item" v-for="(item, index) in formData.accompanyPersons" :key="index">
  75. <view class="form-item">
  76. <text class="label">随行人员</text>
  77. <input class="input" v-model="item.name" placeholder="请输入随行人员姓名"
  78. placeholder-style="color: #c0c4cc" />
  79. </view>
  80. <view class="form-item">
  81. <text class="label">手机号</text>
  82. <input class="input" v-model="item.phone" placeholder="请输入手机号"
  83. placeholder-style="color: #c0c4cc" type="number" />
  84. </view>
  85. <view class="delete-btn" v-if="formData.accompanyPersons.length > 1"
  86. @click.stop="removeAccompany(index)">
  87. <uni-icons type="trash" size="18" color="#ff4757"></uni-icons>
  88. </view>
  89. </view>
  90. </view>
  91. <view class="add-accompany-btn" @click="addAccompany">
  92. <uni-icons type="plus" size="16" color="#007aff"></uni-icons>
  93. <text>添加随行人员</text>
  94. </view>
  95. </view>
  96. <!-- 第四块:使用车辆 -->
  97. <view class="section">
  98. <view class="vehicle-header">
  99. <view class="section-title">
  100. <image class="title-icon" src="/static/images/cart.png" mode="aspectFit"></image>
  101. 使用车辆
  102. </view>
  103. <switch :checked="formData.useVehicle" @change="onVehicleChange" color="#007aff" />
  104. </view>
  105. <view v-if="formData.useVehicle" class="vehicle-content">
  106. <view class="form-item">
  107. <text class="label">接客时间</text>
  108. <uni-datetime-picker type="datetime" v-model="formData.pickupTime" @change="onPickupTimeChange"
  109. :clear-icon="false" placeholder="请选择接客时间" format="YYYY-MM-DD HH:mm" :hide-second="true">
  110. <view class="input-wrapper">
  111. <text class="placeholder" v-if="!formData.pickupTime">请选择接客时间</text>
  112. <text v-else>{{ formData.pickupTime }}</text>
  113. <uni-icons type="calendar" size="16" color="#c0c4cc"></uni-icons>
  114. </view>
  115. </uni-datetime-picker>
  116. </view>
  117. <view class="form-item">
  118. <text class="label">接客地点</text>
  119. <input class="input" v-model="formData.pickupLocation" placeholder="请输入接客地点"
  120. placeholder-style="color: #c0c4cc" />
  121. </view>
  122. </view>
  123. </view>
  124. </view>
  125. <!-- 提交按钮 -->
  126. <view class="submit-container">
  127. <button class="submit-btn" @click="submitForm">提交</button>
  128. </view>
  129. <!-- 提交成功弹框 -->
  130. <!-- <uni-popup ref="successPopup" type="center" :mask-click="false">-->
  131. <!-- <view class="success-popup">-->
  132. <!-- <view class="popup-content">-->
  133. <!-- <view class="success-icon">-->
  134. <!-- <uni-icons type="checkmarkempty" size="60" color="#52c41a"></uni-icons>-->
  135. <!-- </view>-->
  136. <!-- <view class="popup-title">申请提交成功</view>-->
  137. <!-- <view class="popup-message">您的申请已成功提交,请关注公众号即时查询审核结果</view>-->
  138. <!-- <view class="popup-buttons">-->
  139. <!-- <button class="cancel-btn" @click="closeSuccessPopup">取消</button>-->
  140. <!-- <button class="follow-btn" @click="showQRCode">关注</button>-->
  141. <!-- </view>-->
  142. <!-- </view>-->
  143. <!-- </view>-->
  144. <!-- </uni-popup>-->
  145. <!-- 二维码弹框 -->
  146. <!-- <uni-popup ref="qrcodePopup" type="center" :mask-click="false">-->
  147. <!-- <view class="qrcode-popup">-->
  148. <!-- <view class="qrcode-content">-->
  149. <!-- <view class="qrcode-title">扫描二维码关注公众号</view>-->
  150. <!-- <view class="qrcode-image" @click="previewQRCode">-->
  151. <!-- <image src="/static/images/qrcode.png" mode="aspectFit"></image>-->
  152. <!-- <view class="preview-tip">-->
  153. <!-- <uni-icons type="search" size="16" color="#fff"></uni-icons>-->
  154. <!-- <text>点击查看大图</text>-->
  155. <!-- </view>-->
  156. <!-- </view>-->
  157. <!-- <view class="qrcode-tip">扫描上方二维码,关注公众号获取审核结果</view>-->
  158. <!-- <button class="qrcode-close-btn" @click="closeQRCode">我知道了</button>-->
  159. <!-- </view>-->
  160. <!-- </view>-->
  161. <!-- </uni-popup>-->
  162. <uni-popup ref="successPopup" type="bottom" :mask-click="false">
  163. <!-- <view style="height: 100%;width: 100%;background-color: #fff;">-->
  164. <!-- <button>授权登录</button>-->
  165. <!-- <text style="font-size: 24rpx;color: rgba(41,44,53,0.6);line-height: 1.5;">-->
  166. <!-- 登录即代表您已同意-->
  167. <!-- <text style="color: #FF5B05;text-decoration: none;" @tap="goToPrivacy">《隐私政策》</text>-->
  168. <!-- 和-->
  169. <!-- <text style="color: #FF5B05;text-decoration: none;" @tap="goToService">《服务协议》</text>-->
  170. <!-- </text>-->
  171. <!-- </view>-->
  172. <view class="auth-popup">
  173. <view >
  174. <button class="login-btn" @tap="handleLogin">授权登录</button>
  175. <view class="agreement-text">
  176. 登录即代表您已同意
  177. <text class="agreement-link" @tap="goToPrivacy">《隐私政策》</text>
  178. <text class="agreement-link" @tap="goToService">《服务协议》</text>
  179. </view>
  180. </view>
  181. </view>
  182. </uni-popup>
  183. </view>
  184. </template>
  185. <script>
  186. import user from '../../store/modules/user';
  187. import {
  188. getDept,
  189. selectUser,
  190. addVisit
  191. } from '@/config/api.js';
  192. export default {
  193. data() {
  194. return {
  195. type: '', // 从上一页传递过来的参数
  196. tabbarHeight: 50, // tabbar高度,默认50px
  197. user: null, // 用户信息
  198. formData: {
  199. departmentId: '',
  200. department: '',
  201. employeeId: '',
  202. employeeName: '',
  203. visitReason: '',
  204. visitTime: '',
  205. visitorName: '',
  206. visitorCompany: '',
  207. visitorPhone: '',
  208. accompanyPersons: [{
  209. name: '',
  210. phone: ''
  211. }],
  212. useVehicle: false,
  213. pickupTime: '',
  214. pickupLocation: ''
  215. },
  216. // 部门数据
  217. departments: [],
  218. // 部门选项(格式化为uni-data-select所需格式)
  219. departmentOptions: [],
  220. // 员工选项
  221. employeeOptions: [],
  222. }
  223. },
  224. onLoad(options) {
  225. console.log(uni.getStorageSync("user"), "usususuus")
  226. // 获取传递过来的参数
  227. if (options.type) {
  228. this.type = options.type;
  229. }
  230. // 获取用户信息
  231. this.user = uni.getStorageSync("user")
  232. this.getTabbarHeight()
  233. this.getDeptList()
  234. },
  235. onReady() {
  236. // 页面渲染完成后再次获取,确保准确
  237. this.getTabbarHeight()
  238. this.$refs.successPopup.open()
  239. },
  240. methods: {
  241. // 获取tabbar高度
  242. getTabbarHeight() {
  243. // 获取菜单按钮信息,用于计算真实的可用高度
  244. const systemInfo = uni.getSystemInfoSync()
  245. // 在微信小程序中,使用 windowHeight 和 screenHeight 的差值
  246. // windowHeight 是不包含 tabbar 的可用高度
  247. const windowHeight = systemInfo.windowHeight
  248. const screenHeight = systemInfo.screenHeight
  249. // 微信小程序 tabbar 高度通常是 50px,但在不同设备可能不同
  250. // 直接使用差值
  251. let tabbarHeight = screenHeight - windowHeight
  252. console.log('系统信息:', {
  253. screenHeight,
  254. windowHeight,
  255. 计算的tabbar高度: tabbarHeight,
  256. safeAreaBottom: systemInfo.safeAreaInsets?.bottom || systemInfo.safeArea?.bottom || 0
  257. })
  258. // 在小程序中通常是 50-80 之间
  259. // 如果是 H5,差值会包含地址栏等,会更大
  260. // #ifdef MP-WEIXIN
  261. if (tabbarHeight < 30 || tabbarHeight > 100) {
  262. tabbarHeight = 50 // 微信小程序默认 50px
  263. }
  264. // #endif
  265. // #ifdef H5
  266. tabbarHeight = 50 // H5 固定使用 50px
  267. // #endif
  268. this.tabbarHeight = tabbarHeight
  269. },
  270. async getDeptList() {
  271. console.log("获取DEPT")
  272. try {
  273. const res = await getDept({
  274. parentId: 100
  275. })
  276. console.log("部门API返回数据:", res)
  277. this.departments = res.data
  278. // 格式化部门数据为uni-data-select所需格式
  279. this.departmentOptions = res.data.map(item => ({
  280. value: item.dept_id,
  281. text: item.dept_name
  282. }))
  283. console.log("格式化后的部门选项:", this.departmentOptions)
  284. // 添加延时确保数据已经设置
  285. this.$nextTick(() => {
  286. console.log("nextTick后的部门选项:", this.departmentOptions)
  287. })
  288. } catch (error) {
  289. console.error("获取部门列表失败:", error)
  290. uni.showToast({
  291. title: '获取部门列表失败',
  292. icon: 'none'
  293. })
  294. }
  295. },
  296. // 部门选择改变
  297. async onDepartmentSelectChange(value) {
  298. console.log("选择的部门ID:", value)
  299. this.formData.departmentId = value
  300. // 找到选中的部门信息
  301. const selectedDept = this.departments.find(dept => dept.dept_id === value)
  302. if (selectedDept) {
  303. this.formData.department = selectedDept.dept_name
  304. // 根据部门ID获取员工列表
  305. try {
  306. const userRes = await selectUser({
  307. deptId: value
  308. })
  309. console.log("员工列表:", userRes)
  310. // 格式化员工数据为uni-data-select所需格式
  311. if (userRes && userRes.rows) {
  312. this.employeeOptions = userRes.rows.map(item => ({
  313. value: item.user_id,
  314. text: item.nick_name
  315. }))
  316. console.log("格式化后的员工选项:", this.employeeOptions)
  317. } else if (userRes && userRes.data && userRes.data.rows) {
  318. // 备用路径,以防数据结构不同
  319. this.employeeOptions = userRes.data.rows.map(item => ({
  320. value: item.user_id,
  321. text: item.nick_name
  322. }))
  323. console.log("格式化后的员工选项(备用路径):", this.employeeOptions)
  324. }
  325. // 清空之前选择的员工
  326. this.formData.employeeId = ''
  327. this.formData.employeeName = ''
  328. } catch (error) {
  329. console.error("获取员工列表失败:", error)
  330. uni.showToast({
  331. title: '获取员工列表失败',
  332. icon: 'none'
  333. })
  334. }
  335. }
  336. },
  337. // 员工选择改变
  338. onEmployeeSelectChange(value) {
  339. console.log("选择的员工ID:", value)
  340. this.formData.employeeId = value
  341. // 根据employeeOptions找到对应的员工名称
  342. const selectedEmployee = this.employeeOptions.find(emp => emp.value === value)
  343. if (selectedEmployee) {
  344. this.formData.employeeName = selectedEmployee.text
  345. console.log("选择的员工名称:", selectedEmployee.text)
  346. }
  347. },
  348. // 到访时间改变
  349. onVisitTimeChange(e) {
  350. this.formData.visitTime = e;
  351. },
  352. // 接客时间改变
  353. onPickupTimeChange(e) {
  354. this.formData.pickupTime = e;
  355. },
  356. // 获取当前日期时间
  357. getCurrentDatetime() {
  358. const now = new Date();
  359. const year = now.getFullYear();
  360. const month = String(now.getMonth() + 1).padStart(2, '0');
  361. const day = String(now.getDate()).padStart(2, '0');
  362. const hour = String(now.getHours()).padStart(2, '0');
  363. const minute = String(now.getMinutes()).padStart(2, '0');
  364. return `${year}-${month}-${day} ${hour}:${minute}`;
  365. },
  366. // 添加随行人员
  367. addAccompany() {
  368. this.formData.accompanyPersons.push({
  369. name: '',
  370. phone: ''
  371. });
  372. },
  373. // 删除随行人员
  374. removeAccompany(index) {
  375. console.log('删除随行人员,索引:', index, '当前数量:', this.formData.accompanyPersons.length);
  376. if (this.formData.accompanyPersons.length > 1) {
  377. uni.showModal({
  378. title: '确认删除',
  379. content: '确定要删除这个随行人员吗?',
  380. success: (res) => {
  381. if (res.confirm) {
  382. this.formData.accompanyPersons.splice(index, 1);
  383. console.log('删除成功,剩余数量:', this.formData.accompanyPersons.length);
  384. }
  385. }
  386. });
  387. } else {
  388. uni.showToast({
  389. title: '至少保留一个随行人员',
  390. icon: 'none'
  391. });
  392. }
  393. },
  394. // 车辆开关改变
  395. onVehicleChange(e) {
  396. this.formData.useVehicle = e.detail.value;
  397. if (!this.formData.useVehicle) {
  398. // 关闭车辆使用时清空相关信息
  399. this.formData.pickupTime = '';
  400. this.formData.pickupLocation = '';
  401. }
  402. },
  403. // 手机号格式校验
  404. validatePhone(phone) {
  405. const phoneRegex = /^1[3-9]\d{9}$/;
  406. return phoneRegex.test(phone);
  407. },
  408. // 表单验证
  409. validateForm() {
  410. if (!this.formData.department) {
  411. uni.showToast({
  412. title: '请选择所属部门',
  413. icon: 'none'
  414. });
  415. return false;
  416. }
  417. if (!this.formData.employeeName) {
  418. uni.showToast({
  419. title: '请输入员工姓名',
  420. icon: 'none'
  421. });
  422. return false;
  423. }
  424. if (!this.formData.visitReason) {
  425. uni.showToast({
  426. title: '请输入访问事由',
  427. icon: 'none'
  428. });
  429. return false;
  430. }
  431. if (!this.formData.visitTime) {
  432. uni.showToast({
  433. title: '请选择到访时间',
  434. icon: 'none'
  435. });
  436. return false;
  437. }
  438. if (!this.formData.visitorName) {
  439. uni.showToast({
  440. title: '请输入访客姓名',
  441. icon: 'none'
  442. });
  443. return false;
  444. }
  445. // if (!this.formData.visitorCompany) {
  446. // uni.showToast({
  447. // title: '请输入访客单位',
  448. // icon: 'none'
  449. // });
  450. // return false;
  451. // }
  452. if (!this.formData.visitorPhone) {
  453. uni.showToast({
  454. title: '请输入手机号',
  455. icon: 'none'
  456. });
  457. return false;
  458. }
  459. // 校验访客手机号格式
  460. if (!this.validatePhone(this.formData.visitorPhone)) {
  461. uni.showToast({
  462. title: '请输入正确的手机号格式',
  463. icon: 'none'
  464. });
  465. return false;
  466. }
  467. // 验证随行人员信息
  468. for (let i = 0; i < this.formData.accompanyPersons.length; i++) {
  469. const person = this.formData.accompanyPersons[i];
  470. if (person.name && !person.phone) {
  471. uni.showToast({
  472. title: `请输入第${i + 1}个随行人员的手机号`,
  473. icon: 'none'
  474. });
  475. return false;
  476. }
  477. if (!person.name && person.phone) {
  478. uni.showToast({
  479. title: `请输入第${i + 1}个随行人员的姓名`,
  480. icon: 'none'
  481. });
  482. return false;
  483. }
  484. // 校验随行人员手机号格式
  485. if (person.phone && !this.validatePhone(person.phone)) {
  486. uni.showToast({
  487. title: `第${i + 1}个随行人员手机号格式不正确`,
  488. icon: 'none'
  489. });
  490. return false;
  491. }
  492. }
  493. // 验证车辆使用信息
  494. if (this.formData.useVehicle) {
  495. if (!this.formData.pickupTime) {
  496. uni.showToast({
  497. title: '请选择接客时间',
  498. icon: 'none'
  499. });
  500. return false;
  501. }
  502. if (!this.formData.pickupLocation) {
  503. uni.showToast({
  504. title: '请选择接客地点',
  505. icon: 'none'
  506. });
  507. return false;
  508. }
  509. }
  510. return true;
  511. },
  512. // 提交表单
  513. async submitForm() {
  514. if (!this.validateForm()) {
  515. return;
  516. }
  517. // 过滤空的随行人员
  518. const validAccompanyPersons = this.formData.accompanyPersons.filter(person =>
  519. person.name && person.phone
  520. );
  521. // 构建提交数据
  522. const submitData = {
  523. visitDate: this.formData.visitTime, // 访问时间
  524. // userId: this.user?.id || '', // 员工id
  525. empName: this.formData.employeeName, // 访问部门人(员工姓名)
  526. visDept: this.formData.visitorCompany, // 访客单位
  527. visitPerson: this.formData.visitorName, // 访客姓名
  528. visitorTel: this.formData.visitorPhone, // 访客手机
  529. visitorNum: (validAccompanyPersons.length + 1).toString(), // 访问人数(访客+随行人员)
  530. visitReson: this.formData.visitReason, // 访问事由
  531. accPerson: JSON.stringify(validAccompanyPersons) // 随行人员转为JSON字符串
  532. };
  533. console.log('提交数据:', submitData);
  534. try {
  535. // 调用后端接口提交数据
  536. const response = await addVisit(submitData);
  537. console.log('提交成功:', response);
  538. // 显示提交成功弹框
  539. this.$refs.successPopup.open();
  540. } catch (error) {
  541. console.error('提交失败:', error);
  542. uni.showToast({
  543. title: '提交失败,请重试',
  544. icon: 'none'
  545. });
  546. }
  547. },
  548. // 关闭成功弹框
  549. closeSuccessPopup() {
  550. this.$refs.successPopup.close();
  551. // 返回上一页
  552. uni.navigateBack();
  553. },
  554. // 显示二维码
  555. showQRCode() {
  556. this.$refs.successPopup.close();
  557. // this.$refs.qrcodePopup.open();
  558. },
  559. // 关闭二维码弹框
  560. closeQRCode() {
  561. this.$refs.qrcodePopup.close();
  562. // 返回上一页
  563. uni.navigateBack();
  564. },
  565. // 跳转到隐私政策
  566. goToPrivacy() {
  567. uni.navigateTo({
  568. url: '/pagesA/public/richtext'
  569. });
  570. },
  571. // 跳转到服务协议
  572. goToService() {
  573. uni.navigateTo({
  574. url: '/pagesA/public/richtext'
  575. });
  576. },
  577. // 预览二维码
  578. previewQRCode() {
  579. uni.previewImage({
  580. urls: ['/static/images/qrcode.png'],
  581. current: 0
  582. });
  583. },
  584. }
  585. }
  586. </script>
  587. <style lang="scss" scoped>
  588. .container {
  589. background-color: #f5f5f5;
  590. min-height: 100vh;
  591. }
  592. .form-container {
  593. padding: 20rpx;
  594. }
  595. .section {
  596. background-color: #fff;
  597. border-radius: 12rpx;
  598. margin-bottom: 20rpx;
  599. padding: 30rpx;
  600. }
  601. .section-title {
  602. font-size: 32rpx;
  603. font-weight: 600;
  604. color: #333;
  605. margin-bottom: 30rpx;
  606. display: flex;
  607. align-items: center;
  608. }
  609. .title-icon {
  610. width: 40rpx;
  611. height: 40rpx;
  612. margin-right: 15rpx;
  613. }
  614. .form-item {
  615. display: flex;
  616. align-items: center;
  617. margin-bottom: 30rpx;
  618. position: relative;
  619. &:last-child {
  620. margin-bottom: 0;
  621. }
  622. }
  623. .label {
  624. width: 160rpx;
  625. font-size: 28rpx;
  626. color: #666;
  627. flex-shrink: 0;
  628. }
  629. .input {
  630. flex: 1;
  631. height: 70rpx;
  632. padding: 0 20rpx;
  633. background-color: #f8f8f8;
  634. border-radius: 8rpx;
  635. font-size: 28rpx;
  636. color: #333;
  637. }
  638. .input-wrapper {
  639. flex: 1;
  640. height: 70rpx;
  641. padding: 0 20rpx;
  642. background-color: #f8f8f8;
  643. border-radius: 8rpx;
  644. display: flex;
  645. align-items: center;
  646. justify-content: space-between;
  647. }
  648. .placeholder {
  649. color: #c0c4cc;
  650. font-size: 28rpx;
  651. }
  652. .select-wrapper {
  653. flex: 1;
  654. ::v-deep .uni-stat__select {
  655. width: 100%;
  656. }
  657. ::v-deep .uni-stat-box {
  658. width: 100%;
  659. }
  660. ::v-deep .uni-select {
  661. width: 100%;
  662. border: none;
  663. }
  664. ::v-deep .uni-select__input-box {
  665. height: 70rpx;
  666. padding: 0 20rpx;
  667. background-color: #f8f8f8;
  668. border-radius: 8rpx;
  669. border: none;
  670. }
  671. ::v-deep .uni-select__input-text {
  672. font-size: 28rpx;
  673. color: #333;
  674. }
  675. ::v-deep .uni-select__input-placeholder {
  676. color: #c0c4cc;
  677. }
  678. ::v-deep .uni-select__selector {
  679. max-height: 400rpx;
  680. }
  681. }
  682. .accompany-list {
  683. .accompany-item {
  684. position: relative;
  685. padding: 20rpx;
  686. background-color: #f8f8f8;
  687. border-radius: 8rpx;
  688. margin-bottom: 20rpx;
  689. &:last-child {
  690. margin-bottom: 0;
  691. }
  692. }
  693. }
  694. .delete-btn {
  695. position: absolute;
  696. top: 10rpx;
  697. right: 10rpx;
  698. width: 70rpx;
  699. height: 70rpx;
  700. display: flex;
  701. align-items: center;
  702. justify-content: center;
  703. background-color: #fff;
  704. border-radius: 50%;
  705. box-shadow: 0 2rpx 8rpx rgba(0, 0, 0, 0.1);
  706. z-index: 10;
  707. cursor: pointer;
  708. &:active {
  709. opacity: 0.7;
  710. transform: scale(0.95);
  711. }
  712. }
  713. .add-accompany-btn {
  714. display: flex;
  715. align-items: center;
  716. justify-content: center;
  717. height: 80rpx;
  718. background-color: #f8f9fa;
  719. border: 2rpx dashed #c0c4cc;
  720. border-radius: 8rpx;
  721. color: #909399;
  722. font-size: 28rpx;
  723. text {
  724. margin-left: 10rpx;
  725. }
  726. }
  727. .vehicle-header {
  728. display: flex;
  729. align-items: center;
  730. margin-bottom: 30rpx;
  731. .section-title {
  732. flex: 1;
  733. margin-bottom: 0;
  734. margin-left: 15rpx;
  735. }
  736. }
  737. .vehicle-content {
  738. padding-top: 20rpx;
  739. border-top: 1rpx solid #eee;
  740. }
  741. .submit-container {
  742. padding: 20rpx;
  743. background-color: #fff;
  744. margin-top: 20rpx;
  745. }
  746. .submit-btn {
  747. width: 100%;
  748. height: 88rpx;
  749. background: linear-gradient(135deg, #ff6b35 0%, #ff9500 100%);
  750. border-radius: 44rpx;
  751. border: none;
  752. color: #fff;
  753. font-size: 32rpx;
  754. font-weight: 600;
  755. }
  756. .picker-container {
  757. background-color: #fff;
  758. border-radius: 20rpx 20rpx 0 0;
  759. }
  760. .picker-header {
  761. display: flex;
  762. align-items: center;
  763. justify-content: space-between;
  764. padding: 30rpx;
  765. border-bottom: 1rpx solid #eee;
  766. text {
  767. color: #007aff;
  768. font-size: 28rpx;
  769. }
  770. }
  771. .picker-title {
  772. font-size: 32rpx;
  773. font-weight: 600;
  774. color: #333 !important;
  775. }
  776. .picker-view {
  777. height: 400rpx;
  778. }
  779. .picker-item {
  780. display: flex;
  781. align-items: center;
  782. justify-content: center;
  783. height: 80rpx;
  784. font-size: 28rpx;
  785. color: #333;
  786. }
  787. // 提交成功弹框样式
  788. .success-popup {
  789. .popup-content {
  790. background-color: #fff;
  791. border-radius: 20rpx;
  792. padding: 60rpx 40rpx 40rpx;
  793. width: 560rpx;
  794. text-align: center;
  795. }
  796. .success-icon {
  797. margin-bottom: 30rpx;
  798. }
  799. .popup-title {
  800. font-size: 36rpx;
  801. font-weight: 600;
  802. color: #333;
  803. margin-bottom: 20rpx;
  804. }
  805. .popup-message {
  806. font-size: 28rpx;
  807. color: #666;
  808. line-height: 1.6;
  809. margin-bottom: 50rpx;
  810. }
  811. .popup-buttons {
  812. display: flex;
  813. gap: 20rpx;
  814. button {
  815. flex: 1;
  816. height: 80rpx;
  817. border-radius: 40rpx;
  818. font-size: 28rpx;
  819. border: none;
  820. }
  821. .cancel-btn {
  822. background-color: #f5f5f5;
  823. color: #666;
  824. }
  825. .follow-btn {
  826. background: linear-gradient(135deg, #ff6b35 0%, #ff9500 100%);
  827. color: #fff;
  828. }
  829. }
  830. }
  831. // 二维码弹框样式
  832. .qrcode-popup {
  833. .qrcode-content {
  834. background-color: #fff;
  835. border-radius: 20rpx;
  836. padding: 50rpx 40rpx;
  837. width: 560rpx;
  838. text-align: center;
  839. }
  840. .qrcode-title {
  841. font-size: 32rpx;
  842. font-weight: 600;
  843. color: #333;
  844. margin-bottom: 40rpx;
  845. }
  846. .qrcode-image {
  847. width: 400rpx;
  848. height: 400rpx;
  849. margin: 0 auto 30rpx;
  850. border: 1rpx solid #eee;
  851. border-radius: 12rpx;
  852. overflow: hidden;
  853. position: relative;
  854. image {
  855. width: 100%;
  856. height: 100%;
  857. }
  858. .preview-tip {
  859. position: absolute;
  860. left: 0;
  861. right: 0;
  862. bottom: 0;
  863. height: 60rpx;
  864. background: rgba(0, 0, 0, 0.5);
  865. display: flex;
  866. align-items: center;
  867. justify-content: center;
  868. color: #fff;
  869. font-size: 24rpx;
  870. text {
  871. margin-left: 10rpx;
  872. }
  873. }
  874. &:active {
  875. opacity: 0.8;
  876. }
  877. }
  878. .qrcode-tip {
  879. font-size: 26rpx;
  880. color: #999;
  881. margin-bottom: 40rpx;
  882. line-height: 1.5;
  883. }
  884. .qrcode-close-btn {
  885. width: 100%;
  886. height: 80rpx;
  887. background: linear-gradient(135deg, #ff6b35 0%, #ff9500 100%);
  888. border-radius: 40rpx;
  889. color: #fff;
  890. font-size: 28rpx;
  891. border: none;
  892. }
  893. }
  894. .auth-popup {
  895. width: 100%;
  896. background-color: #fff;
  897. border-radius: 24rpx;
  898. padding: 60rpx 40rpx 50rpx;
  899. box-shadow: 0 10rpx 30rpx rgba(0, 0, 0, 0.1);
  900. }
  901. .login-btn {
  902. width: 100%;
  903. height: 88rpx;
  904. background-color: #FF5B05;
  905. color: white;
  906. border: none;
  907. border-radius: 44rpx;
  908. font-size: 32rpx;
  909. font-weight: 600;
  910. margin-bottom: 40rpx;
  911. }
  912. .login-btn:after {
  913. border: none;
  914. }
  915. .agreement-text {
  916. font-size: 24rpx;
  917. color: rgba(41, 44, 53, 0.6);
  918. line-height: 36rpx;
  919. text-align: center;
  920. }
  921. .agreement-link {
  922. color: #FF5B05;
  923. text-decoration: none;
  924. }
  925. </style>