| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358 |
- <template>
- <view class="page-container">
- <view class="store-info-card">
- <view class="card-header">
- <uni-icons type="shop-filled" size="20" color="#3c82f8"></uni-icons>
- <text class="store-name">{{ storeInfo.name }}</text>
- </view>
- <view class="info-row">
- <text class="info-label">店主名称:</text>
- <text class="info-value">{{ storeInfo.owner }}</text>
- </view>
- <view class="info-row">
- <text class="info-label">联系方式:</text>
- <text class="info-value">{{ storeInfo.contact }}</text>
- </view>
- <view class="info-row">
- <text class="info-label">门店地址:</text>
- <text class="info-value">{{ storeInfo.address }}</text>
- </view>
- </view>
- <view class="patrol-content-card">
- <view class="form-item">
- <view class="form-label required">门头照片</view>
- <uni-file-picker
- :value="formData.storefrontPhoto"
- file-mediatype="image"
- mode="grid"
- ref="mentou"
- :limit="1"
- />
- </view>
- <view class="form-item">
- <view class="form-label required">陈列照片</view>
- <uni-file-picker
- :value="formData.displayPhoto"
- file-mediatype="image"
- mode="grid"
- ref="chenlie"
- :limit="9"
- />
- </view>
- <view class="form-item">
- <view class="form-label required">获取位置</view>
- <view class="location-wrapper" @click="getLocation">
- <text class="location-text" :class="{'placeholder': !locationInfo.address}">
- {{ locationInfo.address || '获取当前位置' }}
- </text>
- <uni-icons v-if="!isLocating" type="location-filled" size="20" color="#3c82f8"></uni-icons>
- <view v-if="isLocating" class="loading-spinner"></view>
- </view>
- </view>
- <view class="form-item">
- <view class="form-label">备注</view>
- <textarea
- class="remark-textarea"
- v-model="formData.remarks"
- placeholder="请输入备注信息"
- placeholder-class="placeholder"
- auto-height
- />
- </view>
- </view>
- <view class="footer-save-button">
- <button class="save-btn" @click="submitForm">提 交</button>
- </view>
- </view>
- </template>
- <script>
- import { getRetailDetail, uploadImage,addPatrolRecord,parseLocation} from "@/api/hexiao";
- export default {
- data() {
- return {
- loadding:false,
- // 假设的门店信息,从上个页面传来
- storeInfo: {
- id: 1,
- name: '',
- owner: '',
- contact: '',
- address: ''
- },
- // 表单数据
- formData: {
- storefrontPhoto: [], // 用于 file-picker 显示
- storefrontPhotoUrl: '', // 门头照上传后的URL
- displayPhoto: [], // 用于 file-picker 显示
- displayPhotoUrl: '', // 陈列照上传后的URL
- remarks: ''
- },
- // 位置信息
- locationInfo: {
- latitude: null,
- longitude: null,
- address: ''
- },
- isLocating: false, // 是否正在定位中
- };
- },
- onLoad(opt){
- this.storeInfo.id = opt.id;
- getRetailDetail(opt.id).then(res=>{
- let data = res.data;
- this.storeInfo = {
- id: data.id,
- name: data.store_name,
- owner: data.contact_name,
- contact: data.contact_phone,
- address: data.address,
- }
- })
- },
- methods: {
- // 文件选择后自动上传
- async handleFileSelect(type, e) {
- const tempFile = e.tempFiles[0];
- try {
- const imageUrl = await this.uploadImageToServer(tempFile.path);
- if (type === 'storefrontPhoto') {
- this.formData.storefrontPhotoUrl = imageUrl;
- this.formData.storefrontPhoto = [tempFile];
- } else if (type === 'displayPhoto') {
- this.formData.displayPhotoUrl = imageUrl;
- this.formData.displayPhoto = [tempFile];
- }
- uni.showToast({ title: '上传成功', icon: 'success' });
- } catch (error) {
- uni.showToast({ title: '上传失败', icon: 'none' });
- }
- },
- // 删除图片
- handleFileDelete(type) {
- if (type === 'storefrontPhoto') {
- this.formData.storefrontPhoto = [];
- this.formData.storefrontPhotoUrl = '';
- } else if (type === 'displayPhoto') {
- this.formData.displayPhoto = [];
- this.formData.displayPhotoUrl = '';
- }
- },
- // 获取地理位置
- getLocation() {
- this.isLocating = true;
- let self = this;
- uni.getLocation({
- type: 'gcj02', // 'wgs84' GPS坐标, 'gcj02' 国测局坐标
- isHighAccuracy: true,
- geocode: true, // 获取带有地址信息(仅App和H5支持)
- success: (res) => {
- console.log('当前位置信息:', res);
- this.locationInfo.latitude = res.latitude;
- this.locationInfo.longitude = res.longitude;
- parseLocation(res.latitude, res.longitude).then(res=>{
- if("Success" === res.data.message){
- let formatted_addresses = res.data.result.formatted_addresses
- self.locationInfo.address = formatted_addresses.standard_address
- }else{
- uni.showToast({ title: '解析地址失败', icon: 'none' });
- }
- })
- },
- fail: (err) => {
- uni.showToast({ title: '获取位置失败', icon: 'none' });
- console.error(err);
- },
- complete: () => {
- this.isLocating = false;
- }
- });
- },
- // 提交表单
- async submitForm() {
- if(this.$refs.chenlie.files.length === 0){
- return uni.showToast({ title: '请上传门头照片', icon: 'none' });
- }
- if(this.$refs.mentou.files.length === 0){
- return uni.showToast({ title: '请上传陈列照片', icon: 'none' });
- }
- const chenlieArr = await uploadImage(this.$refs.chenlie.files);
- const mentouArr = await uploadImage(this.$refs.mentou.files);
- // 数据校验
- if(mentouArr.length === 0){
- uni.showToast({ title: '门店照片上传失败,请重试', icon: 'none' });
- return;
- }
- if(chenlieArr.length === 0){
- uni.showToast({ title: '陈列照片上传失败,请重试', icon: 'none' });
- return;
- }
- if (!this.locationInfo.address) {
- return uni.showToast({ title: '请获取当前位置', icon: 'none' });
- }
- if(this.loadding){
- return ;
- }
- this.loadding = true;
- uni.showLoading({ title: '正在提交...' ,mask:true});
- const finalData = {
- storeId: this.storeInfo.id,
- storeImg: mentouArr[0],
- displayImg: chenlieArr,
- latitude: this.locationInfo.latitude,
- longitude: this.locationInfo.longitude,
- address: this.locationInfo.address,
- remark: this.formData.remarks
- };
- let res = await addPatrolRecord(finalData)
- if(res.code == 0){
- uni.showToast({ title: '提交成功', icon: 'success' });
- }else{
- uni.showToast({ title: '提交失败', icon: 'error' });
- }
- uni.hideLoading();
- setTimeout(() => uni.navigateBack(), 1000);
- },
- // 上传图片到您的后端服务器(此方法保持不变)
- uploadImageToServer(tempFilePath) {
- return new Promise((resolve, reject) => {
- uni.uploadFile({
- url: 'https://您的服务器地址/api/upload', // 【重要】请替换
- filePath: tempFilePath,
- name: 'file',
- success: (res) => {
- const data = JSON.parse(res.data);
- if (data.code === 0) {
- resolve(data.data.url);
- } else {
- reject(new Error(data.msg || '上传失败'));
- }
- },
- fail: (err) => { reject(err); }
- });
- });
- }
- }
- }
- </script>
- <style lang="scss" scoped>
- .page-container {
- min-height: 100vh;
- background: linear-gradient(to bottom, #e4efff, #f5f6fa 40%);
- padding: 30rpx;
- box-sizing: border-box;
- padding-bottom: 160rpx; // 为底部按钮留出空间
- }
- .store-info-card, .patrol-content-card {
- background-color: #ffffff;
- border-radius: 20rpx;
- padding: 30rpx;
- box-shadow: 0 4rpx 20rpx rgba(0, 0, 0, 0.05);
- margin-bottom: 30rpx;
- }
- .store-info-card {
- .card-header {
- display: flex;
- align-items: center;
- .store-name { font-size: 32rpx; font-weight: bold; margin-left: 15rpx; }
- }
- .info-row {
- margin-top: 20rpx;
- font-size: 28rpx;
- .info-label { color: #999; }
- .info-value { color: #333; margin-left: 20rpx; }
- }
- }
- .patrol-content-card {
- padding: 10rpx 30rpx;
- }
- .form-item {
- padding: 30rpx 0;
- border-bottom: 1rpx solid #f0f0f0;
- &:last-child { border-bottom: none; }
- }
- .form-label {
- display: block;
- font-size: 30rpx;
- color: #333;
- font-weight: 500;
- margin-bottom: 20rpx;
- &.required::before {
- content: '*';
- color: #e54d42;
- margin-right: 8rpx;
- }
- }
- .location-wrapper {
- display: flex;
- align-items: center;
- justify-content: space-between;
- .location-text {
- font-size: 28rpx;
- color: #333;
- flex: 1;
- &.placeholder { color: #c0c4cc; }
- }
- }
- .remark-textarea {
- width: 100%;
- font-size: 28rpx;
- min-height: 150rpx;
- }
- .placeholder { color: #c0c4cc; }
- .footer-save-button {
- position: fixed;
- left: 0;
- bottom: 0;
- width: 100%;
- padding: 20rpx 30rpx;
- background-color: #f5f6fa;
- box-sizing: border-box;
- padding-bottom: calc(20rpx + constant(safe-area-inset-bottom));
- padding-bottom: calc(20rpx + env(safe-area-inset-bottom));
- }
- .save-btn {
- background-color: #409eff;
- color: #ffffff;
- border-radius: 50rpx;
- font-size: 32rpx;
- height: 90rpx;
- line-height: 90rpx;
- &::after { border: none; }
- }
- .loading-spinner {
- width: 40rpx;
- height: 40rpx;
- border-radius: 50%;
- border: 4rpx solid #f3f3f3;
- border-top-color: #3498db;
- animation: spin 1s linear infinite;
- }
- @keyframes spin {
- to { transform: rotate(360deg); }
- }
- </style>
|