Browse Source

收货地址

tt0101 1 day ago
parent
commit
3e8de8c545
5 changed files with 625 additions and 0 deletions
  1. 0 0
      src/assets/shouhuo.png
  2. 167 0
      src/components/NavBar.vue
  3. 9 0
      src/router/index.js
  4. 0 0
      src/views/Profile.vue
  5. 449 0
      src/views/shdizhi.vue

+ 0 - 0
src/assets/icons8-giveaway-64.png → src/assets/shouhuo.png


+ 167 - 0
src/components/NavBar.vue

@@ -0,0 +1,167 @@
+ <template>
+  <div class="nav-bar">
+    <div class="back-btn" @click="$router.back()" v-if="showBack">
+      <i class="arrow-left"></i>
+    </div>
+    <div class="title">{{ title }}</div>
+    <div class="right-btn" @click="handleRightAction" v-if="rightText || rightIcon">
+      <i v-if="rightIcon" :class="rightIcon"></i>
+      <span v-if="rightText">{{ rightText }}</span>
+    </div>
+  </div>
+</template>
+
+<script>
+export default {
+  name: 'NavBar',
+  props: {
+    // 标题
+    title: {
+      type: String,
+      default: ''
+    },
+    // 是否显示返回按钮
+    showBack: {
+      type: Boolean,
+      default: true
+    },
+    // 右侧文字
+    rightText: {
+      type: String,
+      default: ''
+    },
+    // 右侧图标类名
+    rightIcon: {
+      type: String,
+      default: ''
+    },
+    // 自定义返回处理
+    customBack: {
+      type: Function,
+      default: null
+    },
+    // 右侧按钮点击处理
+    rightAction: {
+      type: Function,
+      default: null
+    },
+    // 背景色
+    backgroundColor: {
+      type: String,
+      default: '#fff'
+    },
+    // 文字颜色
+    textColor: {
+      type: String,
+      default: '#000'
+    }
+  },
+  methods: {
+    // 处理返回按钮点击
+    handleBack() {
+      if (this.customBack) {
+        this.customBack();
+      } else {
+        this.$router.back();
+      }
+      this.$emit('back');
+    },
+    
+    // 处理右侧按钮点击
+    handleRightAction() {
+      if (this.rightAction) {
+        this.rightAction();
+      }
+      this.$emit('right-click');
+    }
+  }
+}
+</script>
+
+<style scoped>
+.nav-bar {
+  height: 44px;
+  background-color: v-bind(backgroundColor);
+  color: v-bind(textColor);
+  display: flex;
+  align-items: center;
+  position: relative;
+  padding: 0 15px;
+  font-weight: bold;
+  box-shadow: 0 1px 3px rgba(0,0,0,0.1);
+  z-index: 1000;
+}
+
+.back-btn {
+  width: 24px;
+  height: 44px;
+  display: flex;
+  align-items: center;
+  cursor: pointer;
+  transition: opacity 0.2s ease;
+}
+
+.back-btn:active {
+  opacity: 0.6;
+}
+
+.arrow-left {
+  width: 12px;
+  height: 12px;
+  border-left: 2px solid currentColor;
+  border-bottom: 2px solid currentColor;
+  transform: rotate(45deg);
+  transition: transform 0.2s ease;
+}
+
+.back-btn:hover .arrow-left {
+  transform: rotate(45deg) translateX(-1px);
+}
+
+.title {
+  position: absolute;
+  left: 50%;
+  transform: translateX(-50%);
+  font-size: 16px;
+  max-width: calc(100% - 120px);
+  overflow: hidden;
+  text-overflow: ellipsis;
+  white-space: nowrap;
+}
+
+.right-btn {
+  position: absolute;
+  right: 15px;
+  height: 44px;
+  display: flex;
+  align-items: center;
+  cursor: pointer;
+  transition: opacity 0.2s ease;
+  font-size: 14px;
+}
+
+.right-btn:active {
+  opacity: 0.6;
+}
+
+.right-btn i {
+  font-size: 16px;
+  margin-right: 4px;
+}
+
+.right-btn span {
+  font-weight: 500;
+}
+
+/* 响应式优化 */
+@media screen and (max-width: 375px) {
+  .title {
+    max-width: calc(100% - 100px);
+    font-size: 15px;
+  }
+  
+  .right-btn {
+    font-size: 13px;
+  }
+}
+</style>

+ 9 - 0
src/router/index.js

@@ -31,6 +31,7 @@ import Medical from '@/views/Medical.vue'
 import China from '@/views/China.vue'
 import Jifen from '@/views/jifen.vue'
 import Dhjilu from '@/views/dhjilu.vue'
+import Dizhi from '@/views/shdizhi.vue'
 Vue.use(VueRouter);
 
 const routes = [
@@ -258,6 +259,14 @@ const routes = [
       hideTabBar: true
   },
   },
+  {
+    path: "/dizhi",
+    name: "Dizhi",
+    component: Dizhi,
+    meta: {
+      hideTabBar: true
+  },
+  },
 ];
 
 const router = new VueRouter({

File diff suppressed because it is too large
+ 0 - 0
src/views/Profile.vue


+ 449 - 0
src/views/shdizhi.vue

@@ -0,0 +1,449 @@
+<template>
+  <div>
+    <!-- 使用封装的导航栏组件 -->
+    <NavBar title="收货地址" @back="handleBack" />
+
+    <!-- 主容器 -->
+    <div class="address-container">
+      <!-- 顶部插画卡片 -->
+      <div class="header-card">
+        <div class="card-content">
+          <div class="text-section">
+            <h3>收货地址</h3>
+          </div>
+          <div class="illustration">
+            <img src="@/assets/shouhuo.png" alt="收货地址">
+          </div>
+        </div>
+      </div>
+
+      <!-- 地址信息表单 -->
+      <div class="form-card">
+        <h4 class="form-title">填写收货信息</h4>
+        
+        <div class="form-group">
+          <label class="form-label">收货姓名:</label>
+          <input 
+            type="text" 
+            v-model="addressForm.name"
+            class="form-input" 
+            placeholder="请输入收货人姓名"
+            maxlength="20"
+          />
+        </div>
+
+        <div class="form-group">
+          <label class="form-label">收货电话:</label>
+          <input 
+            type="tel" 
+            v-model="addressForm.phone"
+            class="form-input" 
+            placeholder="请输入收货人电话"
+            maxlength="11"
+          />
+        </div>
+
+        <div class="form-group">
+          <label class="form-label">收货地址:</label>
+          <textarea 
+            v-model="addressForm.address"
+            class="form-textarea" 
+            placeholder="请输入收货人地址"
+            rows="3"
+            maxlength="200"
+          ></textarea>
+        </div>
+
+        <!-- 保存按钮 -->
+        <div class="button-wrapper">
+          <button 
+            class="save-btn"
+            @click="saveAddress"
+            :disabled="!isFormValid"
+          >
+            保存地址
+          </button>
+        </div>
+      </div>
+    </div>
+
+    <!-- Toast 提示 -->
+    <Toast ref="toast" />
+  </div>
+</template>
+
+<script>
+import Toast from '@/components/Toast.vue';
+import NavBar from '@/components/NavBar.vue';
+
+export default {
+  name: 'ShdizhiPage',
+  components: {
+    Toast,
+    NavBar
+  },
+  data() {
+    return {
+      addressForm: {
+        name: '',
+        phone: '',
+        address: ''
+      }
+    }
+  },
+  computed: {
+    // 表单验证
+    isFormValid() {
+      return this.addressForm.name.trim() && 
+             this.addressForm.phone.trim() && 
+             this.addressForm.address.trim() &&
+             this.isValidPhone(this.addressForm.phone);
+    }
+  },
+  mounted() {
+    this.loadSavedAddress();
+  },
+  methods: {
+    // 自定义返回处理
+    handleBack() {
+      // 可以在这里添加自定义逻辑,比如询问是否保存草稿
+      if (this.hasUnsavedChanges()) {
+        this.$refs.toast.show('检测到未保存的更改', 'warning');
+        // 可以显示确认对话框
+        return;
+      }
+      this.$router.back();
+    },
+
+    // 检查是否有未保存的更改
+    hasUnsavedChanges() {
+      const current = this.addressForm;
+      const saved = localStorage.getItem('userAddress');
+      
+      if (!saved && (current.name || current.phone || current.address)) {
+        return true;
+      }
+      
+      if (saved) {
+        const savedData = JSON.parse(saved);
+        return current.name !== savedData.name || 
+               current.phone !== savedData.phone || 
+               current.address !== savedData.address;
+      }
+      
+      return false;
+    },
+
+    // 加载已保存的地址
+    async loadSavedAddress() {
+      try {
+        const savedAddress = localStorage.getItem('userAddress');
+        if (savedAddress) {
+          this.addressForm = JSON.parse(savedAddress);
+        }
+      } catch (error) {
+        console.error('加载地址失败:', error);
+      }
+    },
+
+    // 验证手机号
+    isValidPhone(phone) {
+      const phoneRegex = /^1[3-9]\d{9}$/;
+      return phoneRegex.test(phone);
+    },
+
+    // 保存地址
+    async saveAddress() {
+      if (!this.isFormValid) {
+        this.$refs.toast.show('请填写完整的收货信息', 'error');
+        return;
+      }
+
+      if (!this.isValidPhone(this.addressForm.phone)) {
+        this.$refs.toast.show('请输入正确的手机号码', 'error');
+        return;
+      }
+
+      try {
+        localStorage.setItem('userAddress', JSON.stringify(this.addressForm));
+        this.$refs.toast.show('地址保存成功!', 'success');
+        
+        setTimeout(() => {
+          this.$router.back();
+        }, 1500);
+        
+      } catch (error) {
+        console.error('保存地址失败:', error);
+        this.$refs.toast.show('保存失败,请重试', 'error');
+      }
+    }
+  }
+}
+</script>
+
+<style scoped>
+/* 主容器 */
+.address-container {
+  min-height: calc(100vh - 44px);
+  background: linear-gradient(135deg, #c94545 0%, #b43a39 100%);
+  padding: 20px;
+  padding-bottom: 100px;
+}
+
+/* 其他样式保持不变... */
+.header-card {
+  background: #ffc5b9;
+  border-radius: 16px;
+  padding: 15px 10px;
+  margin-bottom: 20px;
+  box-shadow: 0 4px 12px rgba(0,0,0,0.1);
+  position: relative;
+  overflow: hidden;
+}
+
+.card-content {
+  display: flex;
+  justify-content: space-between;
+  align-items: center;
+}
+
+.text-section h3 {
+  font-size: 20px;
+  font-weight: 600;
+  color: #d91d42;
+  margin: 0;
+}
+
+/* 插画样式 */
+.illustration {
+  position: relative;
+  width: 100px;
+  height: 100px;
+  img{
+    width: 100%;
+    height: 100%;
+  }
+}
+
+.person {
+  position: relative;
+  z-index: 2;
+}
+
+.head {
+  width: 24px;
+  height: 24px;
+  background: #ffd700;
+  border-radius: 50%;
+  position: absolute;
+  top: 0;
+  left: 50%;
+  transform: translateX(-50%);
+}
+
+.body {
+  width: 30px;
+  height: 40px;
+  background: #8b5cf6;
+  border-radius: 15px 15px 8px 8px;
+  position: absolute;
+  top: 20px;
+  left: 50%;
+  transform: translateX(-50%);
+}
+
+.gift-box {
+  position: absolute;
+  top: 15px;
+  right: -10px;
+}
+
+.box-body {
+  width: 20px;
+  height: 15px;
+  background: #ffd700;
+  border-radius: 2px;
+}
+
+.ribbon {
+  width: 20px;
+  height: 3px;
+  background: #ff6b6b;
+  position: absolute;
+  top: 6px;
+  left: 0;
+}
+
+.bow {
+  width: 8px;
+  height: 6px;
+  background: #ff6b6b;
+  border-radius: 4px 4px 0 0;
+  position: absolute;
+  top: 3px;
+  left: 6px;
+}
+
+.bow::before,
+.bow::after {
+  content: '';
+  position: absolute;
+  width: 4px;
+  height: 4px;
+  background: #ff6b6b;
+  border-radius: 50%;
+  top: -2px;
+}
+
+.bow::before {
+  left: -2px;
+}
+
+.bow::after {
+  right: -2px;
+}
+
+.shadow {
+  position: absolute;
+  bottom: 0;
+  left: 50%;
+  transform: translateX(-50%);
+  width: 40px;
+  height: 8px;
+  background: rgba(0,0,0,0.1);
+  border-radius: 50%;
+  z-index: 1;
+}
+
+/* 表单卡片 */
+.form-card {
+  background: white;
+  border-radius: 16px;
+  padding: 25px 20px;
+  box-shadow: 0 4px 12px rgba(0,0,0,0.1);
+}
+
+.form-title {
+  font-size: 18px;
+  font-weight: 600;
+  color: #333;
+  margin: 0 0 25px 0;
+}
+
+.form-group {
+  margin-bottom: 20px;
+  display: flex;    
+  align-items: center;
+}
+
+.form-label {
+  display: block;
+  font-size: 16px;
+  font-weight: 500;
+  color: #333;
+  margin-bottom: 8px;
+  width: 100px;
+  white-space: nowrap;
+}
+
+.form-input,
+.form-textarea {
+  width: 100%;
+  padding: 12px 15px;
+  font-size: 15px;
+  color: #333;
+  box-sizing: border-box;
+  border:none;
+}
+
+.form-input:focus,
+.form-textarea:focus {
+  outline: none;
+  border-bottom: 1px solid #c94545;
+}
+
+.form-textarea {
+  resize: vertical;
+  min-height: 80px;
+  line-height: 1.5;
+}
+
+.form-input::placeholder,
+.form-textarea::placeholder {
+  color: #bbb;
+}
+
+/* 按钮样式 */
+.button-wrapper {
+  margin-top: 30px;
+}
+
+.save-btn {
+  width: 100%;
+  background: #c94545;
+  color: white;
+  border: none;
+  border-radius: 25px;
+  padding: 15px 0;
+  font-size: 16px;
+  font-weight: 600;
+  cursor: pointer;
+  transition: all 0.3s ease;
+  box-shadow: 0 4px 12px rgba(201, 69, 69, 0.3);
+}
+
+.save-btn:hover {
+  background: #b43a39;
+  transform: translateY(-1px);
+  box-shadow: 0 6px 16px rgba(201, 69, 69, 0.4);
+}
+
+.save-btn:active {
+  transform: translateY(0);
+}
+
+.save-btn:disabled {
+  background: #ccc;
+  cursor: not-allowed;
+  transform: none;
+  box-shadow: none;
+}
+
+/* 响应式优化 */
+@media screen and (max-width: 375px) {
+  .address-container {
+    padding: 15px;
+  }
+  
+  .header-card {
+    padding: 20px 15px;
+  }
+  
+  .form-card {
+    padding: 20px 15px;
+  }
+  
+  .text-section h3 {
+    font-size: 18px;
+  }
+  
+  
+}
+
+@media screen and (max-width: 320px) {
+  .form-input,
+  .form-textarea {
+    padding: 10px 12px;
+    font-size: 14px;
+  }
+  
+  .form-label {
+    font-size: 15px;
+  }
+  
+  .save-btn {
+    padding: 12px 0;
+    font-size: 15px;
+  }
+}
+</style>

Some files were not shown because too many files changed in this diff