zhangwencui
6 天以前 7ab410022cbf32fd0eb1fe94456a13c95d4a3f89
src/pages/cooperativeOffice/clientVisit/detail.vue
@@ -1,328 +1,360 @@
<template>
  <view class="client-visit-detail">
    <PageHeader title="客户拜访详情" @back="goBack" />
    <u-form @submit="handleSignIn" ref="formRef" label-width="90">
    <PageHeader title="客户拜访详情"
                @back="goBack" />
    <u-form @submit="handleSignIn"
            ref="formRef"
            label-width="90">
      <!-- 客户信息 -->
      <u-cell-group title="客户信息">
        <u-form-item label="客户名称" prop="customerName" required border-bottom>
          <u-input
            v-model="form.customerName"
            placeholder="请输入客户名称"
          />
        <u-form-item label="客户名称"
                     prop="customerName"
                     required
                     border-bottom>
          <u-input v-model="form.customerName"
                   placeholder="请输入客户名称" />
        </u-form-item>
        <u-form-item label="联系人" prop="contact" border-bottom>
          <u-input
            v-model="form.contact"
            placeholder="请输入联系人"
          />
        <u-form-item label="联系人"
                     prop="contact"
                     border-bottom>
          <u-input v-model="form.contact"
                   placeholder="请输入联系人" />
        </u-form-item>
        <u-form-item label="联系电话" prop="contactPhone" border-bottom>
          <u-input
            v-model="form.contactPhone"
            placeholder="请输入联系电话"
          />
        <u-form-item label="联系电话"
                     prop="contactPhone"
                     border-bottom>
          <u-input v-model="form.contactPhone"
                   placeholder="请输入联系电话" />
        </u-form-item>
      </u-cell-group>
      <!-- 拜访信息 -->
      <u-cell-group title="拜访信息">
        <u-form-item label="拜访目的" prop="purposeVisit" required border-bottom>
          <u-input
            v-model="form.purposeVisit"
            placeholder="请输入拜访目的"
          />
        <u-form-item label="拜访目的"
                     prop="purposeVisit"
                     required
                     border-bottom>
          <u-input v-model="form.purposeVisit"
                   placeholder="请输入拜访目的" />
        </u-form-item>
        <u-form-item label="拜访时间" prop="purposeDate" required border-bottom>
          <u-input
            v-model="form.purposeDate"
            placeholder="请选择拜访时间"
            readonly
            @click="showTimePicker"
          />
        <u-form-item label="拜访时间"
                     prop="purposeDate"
                     required
                     border-bottom>
          <u-input v-model="form.purposeDate"
                   placeholder="请选择拜访时间"
                   @click="showTimePicker" />
          <template #right>
               <up-icon
                  name="arrow-right"
                  @click="showTimePicker"
               ></up-icon>
            </template>
            <up-icon name="arrow-right"
                     @click="showTimePicker"></up-icon>
          </template>
        </u-form-item>
        <u-form-item label="拜访地点" prop="visitAddress" required border-bottom>
          <u-input
            v-model="form.visitAddress"
            placeholder="请输入拜访地点"
          >
        <u-form-item label="拜访地点"
                     prop="visitAddress"
                     required
                     border-bottom>
          <u-input v-model="form.visitAddress"
                   placeholder="请输入拜访地点">
            <template #suffix>
              <u-icon name="map" @click.stop="getCurrentLocation" class="location-icon" />
              <u-icon name="map"
                      @click="getCurrentLocation"
                      class="location-icon" />
            </template>
          </u-input>
        </u-form-item>
      </u-cell-group>
      <!-- 备注信息 -->
      <u-cell-group title="备注信息">
        <u-form-item label="备注" prop="remark" border-bottom>
          <u-textarea
            v-model="form.remark"
            placeholder="请输入备注信息"
            :maxlength="200"
            count
            :autoHeight="true"
          />
        <u-form-item label="备注"
                     prop="remark"
                     border-bottom>
          <u-textarea v-model="form.remark"
                      placeholder="请输入备注信息"
                      :maxlength="200"
                      count
                      :autoHeight="true" />
        </u-form-item>
      </u-cell-group>
      <!-- 提交按钮 -->
      <view class="footer-btns">
        <u-button class="cancel-btn" @click="goBack">取消</u-button>
        <u-button class="sign-btn" type="primary" @click="handleSignIn" :loading="loading">签到</u-button>
        <u-button class="cancel-btn"
                  @click="goBack">取消</u-button>
        <u-button class="sign-btn"
                  type="primary"
                  @click="handleSignIn"
                  :loading="loading">签到</u-button>
      </view>
    </u-form>
    <!-- 时间选择器 -->
    <up-datetime-picker
               :show="showTime"
               v-model="currentTime"
               @confirm="onTimeConfirm"
               @cancel="showTime = false"
               mode="datetime"
            />
    <up-datetime-picker :show="showTime"
                        v-model="currentTime"
                        @confirm="onTimeConfirm"
                        @cancel="showTime = false"
                        mode="datetime" />
  </view>
</template>
<script setup>
// 替换 toast 方法
defineOptions({name: 'client-visit-detail'})
const showToast = (message) => {
  uni.showToast({
    title: message,
    icon: 'none'
  })
}
  // 替换 toast 方法
  defineOptions({ name: "client-visit-detail" });
  const showToast = message => {
    uni.showToast({
      title: message,
      icon: "none",
    });
  };
import { ref, onMounted } from 'vue'
import { onShow } from '@dcloudio/uni-app'
import PageHeader from '@/components/PageHeader.vue'
import { clientVisitSignIn } from '@/api/cooperativeOffice/clientVisit'
import useUserStore from "@/store/modules/user"
import dayjs from "dayjs"
import { formatDateToYMD } from '@/utils/ruoyi'
  import { ref, onMounted } from "vue";
  import PageHeader from "@/components/PageHeader.vue";
  import {
    clientVisitSignIn,
    clientVisitUpdate,
  } from "@/api/cooperativeOffice/clientVisit";
  import useUserStore from "@/store/modules/user";
  import dayjs from "dayjs";
  import { onLoad } from "@dcloudio/uni-app";
const userStore = useUserStore()
  const userStore = useUserStore();
// 表单数据
const form = ref({
  customerName: '',
  contact: '',
  contactPhone: '',
  visitingPeople: '',
  purposeVisit: '',
  purposeDate: '',
  visitAddress: '',
  latitude: '',
  longitude: '',
  locationAddress: '',
  remark: ''
})
  // 表单数据
  const form = ref({
    customerName: "",
    contact: "",
    contactPhone: "",
    visitingPeople: "",
    purposeVisit: "",
    purposeDate: "",
    visitAddress: "",
    latitude: "",
    longitude: "",
    locationAddress: "",
    remark: "",
  });
// 页面状态
const loading = ref(false)
const formRef = ref(null)
  // 页面状态
  const loading = ref(false);
  const formRef = ref(null);
// 时间相关
const currentTime = ref(Date.now())
const showTime = ref(false)
  // 时间相关
  const currentTime = ref(Date.now());
  const showTime = ref(false);
// 返回上一页
const goBack = () => {
  uni.navigateBack()
}
  // 返回上一页
  const goBack = () => {
    // 返回时清除本地存储的ID
    uni.removeStorageSync("clientVisit");
    uni.navigateBack();
  };
// 显示时间选择器
const showTimePicker = () => {
  showTime.value = true
}
  // 显示时间选择器
  const showTimePicker = () => {
    showTime.value = true;
  };
// 确认时间选择
const onTimeConfirm = (e) => {
  console.log(e)
  form.value.purposeDate = e.value
   currentTime.value = e.value
   showTime.value = false;
}
  // 确认时间选择
  const onTimeConfirm = e => {
    console.log(e);
    form.value.purposeDate = dayjs(e.value).format("YYYY-MM-DD HH:mm:ss");
    currentTime.value = e.value;
    showTime.value = false;
  };
// 获取当前位置
const getCurrentLocation = () => {
  uni.showLoading({ title: '获取位置中...' })
  uni.getLocation({
    type: 'gcj02',
    success: (res) => {
      form.value.latitude = res.latitude
      form.value.longitude = res.longitude
      // 使用逆地理编码获取地址信息
      uni.request({
        url: `https://restapi.amap.com/v3/geocode/regeo?key=c120a5dc69a9f61839f7763e6057005f&location=${res.longitude},${res.latitude}&radius=1000&extensions=all`,
        success: (geoRes) => {
          uni.hideLoading()
          if (geoRes.data.status === '1' && geoRes.data.regeocode) {
            const regeocode = geoRes.data.regeocode
            const address = regeocode.formatted_address
            // 优先显示详细地址
            if (address) {
              form.value.visitAddress = address
              showToast('位置获取成功')
  // 获取当前位置
  const getCurrentLocation = () => {
    uni.showLoading({ title: "获取位置中..." });
    uni.getLocation({
      type: "gcj02",
      success: res => {
        form.value.latitude = res.latitude;
        form.value.longitude = res.longitude;
        // 使用逆地理编码获取地址信息
        uni.request({
          url: `https://restapi.amap.com/v3/geocode/regeo?key=c120a5dc69a9f61839f7763e6057005f&location=${res.longitude},${res.latitude}&radius=1000&extensions=all`,
          success: geoRes => {
            uni.hideLoading();
            if (geoRes.data.status === "1" && geoRes.data.regeocode) {
              const regeocode = geoRes.data.regeocode;
              const address = regeocode.formatted_address;
              // 优先显示详细地址
              if (address) {
                form.value.visitAddress = address;
                showToast("位置获取成功");
              } else {
                // 如果没有详细地址,尝试组合地址信息
                const addressComponent = regeocode.addressComponent;
                const combinedAddress = `${addressComponent.province}${addressComponent.city}${addressComponent.district}${addressComponent.township}`;
                form.value.visitAddress = combinedAddress;
                showToast("位置获取成功");
              }
            } else {
              // 如果没有详细地址,尝试组合地址信息
              const addressComponent = regeocode.addressComponent
              const combinedAddress = `${addressComponent.province}${addressComponent.city}${addressComponent.district}${addressComponent.township}`
              form.value.visitAddress = combinedAddress
              showToast('位置获取成功')
              // API调用成功但没有返回地址信息
              const fallbackAddress = `位置: ${res.latitude.toFixed(
                4
              )}, ${res.longitude.toFixed(4)}`;
              form.value.visitAddress = fallbackAddress;
              showToast("获取到位置,但地址解析失败");
            }
          } else {
            // API调用成功但没有返回地址信息
            const fallbackAddress = `位置: ${res.latitude.toFixed(4)}, ${res.longitude.toFixed(4)}`
            form.value.visitAddress = fallbackAddress
            showToast('获取到位置,但地址解析失败')
          }
        },
        fail: (err) => {
          uni.hideLoading()
          console.error('逆地理编码失败:', err)
          // 逆地理编码失败时,显示简化的位置信息
          const fallbackAddress = `位置: ${res.latitude.toFixed(4)}, ${res.longitude.toFixed(4)}`
          form.value.visitAddress = fallbackAddress
          showToast('位置获取成功,但地址解析失败')
          },
          fail: err => {
            uni.hideLoading();
            console.error("逆地理编码失败:", err);
            // 逆地理编码失败时,显示简化的位置信息
            const fallbackAddress = `位置: ${res.latitude.toFixed(
              4
            )}, ${res.longitude.toFixed(4)}`;
            form.value.visitAddress = fallbackAddress;
            showToast("位置获取成功,但地址解析失败");
          },
        });
      },
      fail: err => {
        uni.hideLoading();
        showToast("获取位置失败,请检查定位权限");
        console.error("获取位置失败:", err);
        // 失败时显示错误信息
        form.value.visitAddress = "位置获取失败";
      },
    });
  };
  // 提交签到
  const handleSignIn = async () => {
    if (!form.value.customerName) {
      showToast("请输入客户名称");
      return;
    }
    if (!form.value.purposeVisit) {
      showToast("请输入拜访目的");
      return;
    }
    if (!form.value.purposeDate) {
      showToast("请选择拜访时间");
      return;
    }
    if (!form.value.visitAddress) {
      showToast("请获取当前位置");
      return;
    }
    try {
      loading.value = true;
      // 使用安全浅拷贝,避免对象展开在某些运行时抛错
      const source =
        form.value && typeof form.value === "object" ? form.value : {};
      const submitData = {};
      Object.keys(source).forEach(k => {
        submitData[k] = source[k];
      });
      console.log("submitData", submitData);
      if (isEdit.value) {
        const { code } = await clientVisitUpdate(submitData);
        if (code === 200) {
          showToast("修改成功");
          setTimeout(() => {
            goBack();
          }, 500);
        } else {
          loading.value = false;
          showToast("签到失败,请重试");
        }
      })
    },
    fail: (err) => {
      uni.hideLoading()
      showToast('获取位置失败,请检查定位权限')
      console.error('获取位置失败:', err)
      // 失败时显示错误信息
      form.value.visitAddress = '位置获取失败'
      } else {
        const { code } = await clientVisitSignUp(submitData);
        if (code === 200) {
          showToast("签到成功");
          setTimeout(() => {
            goBack();
          }, 500);
        } else {
          loading.value = false;
          showToast("签到失败,请重试");
        }
      }
    } catch (e) {
      loading.value = false;
      console.error("签到失败:", e);
    }
  })
}
// 提交签到
const handleSignIn = async () => {
  if (!form.value.customerName) {
    showToast('请输入客户名称')
    return
  }
  if (!form.value.purposeVisit) {
    showToast('请输入拜访目的')
    return
  }
  if (!form.value.purposeDate) {
    showToast('请选择拜访时间')
    return
  }
  if (!form.value.visitAddress) {
    showToast('请获取当前位置')
    return
  }
  try {
    loading.value = true
    // 使用安全浅拷贝,避免对象展开在某些运行时抛错
    const source = (form.value && typeof form.value === 'object') ? form.value : {}
    const submitData = {}
    Object.keys(source).forEach((k) => {
      submitData[k] = source[k]
    })
    console.log('提交数据:', submitData)
    const { code } = await clientVisitSignIn(submitData)
    console.log('code----', code);
    if (code === 200) {
      showToast('签到成功')
      setTimeout(() => {
        uni.navigateBack()
      }, 500)
  };
  const isEdit = ref(false);
  onLoad(() => {
    // 编辑拜访时,从本地存储获取拜访记录
    const visit = uni.getStorageSync("clientVisit");
    if (visit) {
      form.value = visit;
      isEdit.value = true;
      console.log("form.value", form.value);
    } else {
      loading.value = false
      showToast('签到失败,请重试')
      isEdit.value = false;
    }
  } catch (e) {
    loading.value = false
    showToast('签到失败,请检查网络连接')
    console.error('签到失败:', e)
  }
}
  });
// 初始化页面数据
const initPageData = () => {
  // 设置默认拜访时间为当前时间
  form.value.purposeDate = dayjs().format('YYYY-MM-DD HH:mm:ss')
  currentTime.value = Date.now()
  // 设置拜访人为当前登录用户的昵称
  form.value.visitingPeople = userStore.nickName || ''
}
  // 初始化页面数据
  const initPageData = () => {
    // 设置默认拜访时间为当前时间
    form.value.purposeDate = dayjs().format("YYYY-MM-DD HH:mm:ss");
    currentTime.value = Date.now();
onMounted(() => {
  initPageData()
})
    // 设置拜访人为当前登录用户的昵称
    form.value.visitingPeople = userStore.nickName || "";
  };
  onMounted(() => {
    initPageData();
  });
</script>
<style scoped lang="scss">
@import '@/static/scss/form-common.scss';
.client-visit {
  min-height: 100vh;
  background: #f8f9fa;
  padding-bottom: 5rem;
}
  @import "@/static/scss/form-common.scss";
  .client-visit {
    min-height: 100vh;
    background: #f8f9fa;
    padding-bottom: 5rem;
  }
.footer-btns {
  position: fixed;
  left: 0;
  right: 0;
  bottom: 0;
  background: #fff;
  display: flex;
  justify-content: space-around;
  align-items: center;
  padding: 0.75rem 0;
  box-shadow: 0 -0.125rem 0.5rem rgba(0,0,0,0.05);
  z-index: 1000;
}
  .footer-btns {
    position: fixed;
    left: 0;
    right: 0;
    bottom: 0;
    background: #fff;
    display: flex;
    justify-content: space-around;
    align-items: center;
    padding: 0.75rem 0;
    box-shadow: 0 -0.125rem 0.5rem rgba(0, 0, 0, 0.05);
    z-index: 1000;
  }
.cancel-btn {
  font-weight: 400;
  font-size: 1rem;
  color: #666;
  background: #f5f5f5;
  border: 1px solid #ddd;
  width: 45%;
  height: 2.5rem;
  border-radius: 2.5rem 2.5rem 2.5rem 2.5rem;
}
  .cancel-btn {
    font-weight: 400;
    font-size: 1rem;
    color: #666;
    background: #f5f5f5;
    border: 1px solid #ddd;
    width: 45%;
    height: 2.5rem;
    border-radius: 2.5rem 2.5rem 2.5rem 2.5rem;
  }
.sign-btn {
  font-weight: 500;
  font-size: 1rem;
  color: #fff;
  background: linear-gradient(135deg, #667eea 0%, #764ba2 100%);
  border: none;
  width: 45%;
  height: 2.5rem;
  border-radius: 2.5rem 2.5rem 2.5rem 2.5rem;
}
  .sign-btn {
    font-weight: 500;
    font-size: 1rem;
    color: #fff;
    background: linear-gradient(135deg, #667eea 0%, #764ba2 100%);
    border: none;
    width: 45%;
    height: 2.5rem;
    border-radius: 2.5rem 2.5rem 2.5rem 2.5rem;
  }
.location-icon {
  color: #1989fa;
  font-size: 1.2rem;
}
  .location-icon {
    color: #1989fa;
    font-size: 1.2rem;
  }
</style>