gift/pages/index/index.vue
2025-08-04 18:10:22 +08:00

640 lines
16 KiB
Vue
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

<template>
<view class="content">
<image :src="bg" style="width: 100%; height: 100%; background-color: bisque; position: absolute;" mode="">
</image>
<uniNoticeBar showIcon single scrollable text="赠品仅限线下购买设备的用户领取需人工审核预计3个工作日内完成"
style="width: 100%;position:fixed;top:10%" background-color="transparent" color="#000" />
<view class="auto-scroll-container" catchtouchmove="return false">
<!-- 滚动容器 -->
<scroll-view class="scroll-view" scroll-x :scroll-with-animation="false" ref="scrollView"
@scroll="onScroll">
<!-- 图片列表容器 (复制一份实现无缝滚动) -->
<view class="scroll-content" :style="{ transform: `translateX(${translateX}px)` }"
catchtouchmove="return false">
<view class="image-list" ref="imageList">
<view class="image-item" v-for="(item, index) in imageList" :key="index">
<image :src="item.url" mode="aspectFill" class="item-image" :alt="item.alt"></image>
</view>
</view>
<!-- 复制一份列表用于无缝衔接 -->
<view class="image-list copy-list" catchtouchmove="return false">
<view class="image-item" v-for="(item, index) in imageList" :key="'copy-' + index">
<image :src="item.url" mode="aspectFill" class="item-image" :alt="item.alt"></image>
</view>
</view>
</view>
</scroll-view>
</view>
<view class="center" @click="openReceivePop"
style="width: 386rpx; height: 102rpx; background-color: #0877FF; border-radius: 16rpx; position: absolute; bottom: 200rpx;">
<text style="font-size: 35rpx; color: white;">设备专属权益兑换</text>
</view>
<view class="center" @click="openRecordPop"
style="width: 386rpx; height: 80rpx; border-radius: 16rpx; position: absolute; bottom: 100rpx;">
<text style="font-size: 30rpx; color: black;">领取记录</text>
</view>
<!-- 领奖弹窗 -->
<uni-popup ref="receivePop" type="center" :is-mask-click="false">
<view class="column"
style="width: 600rpx; height: 1250rpx; background-color: #F5F5F5; border-radius: 16rpx; align-items: center; font-size: 25rpx;">
<text style="font-size: 35rpx; font-weight: 600; color: black; margin-top: 40rpx;">恭喜您获得赠礼</text>
<text style="font-size: 25rpx; color: black; margin-top: 10rpx;">填写地址和产品信息,送货上门</text>
<view class="column"
style="width: 550rpx; background-color: white; align-items: center;margin-top: 20rpx;border-radius: 16rpx; padding-bottom: 20rpx;">
<text style="font-size: 25rpx; color: black; margin-top: 10rpx;">收货地址填写</text>
<view class="row line">
<text style="width: 110rpx;">姓名</text>
<input v-model="name" type="text" style="margin-left: 50rpx; width: 350rpx;" />
</view>
<view class="row line">
<text style="width: 110rpx;">联系方式</text>
<input v-model="phone" type="text" style=" margin-left: 50rpx; width: 350rpx;" />
</view>
<view class="row line">
<text style="width: 110rpx;">工作单位</text>
<input v-model="workUnit" type="text" style="margin-left: 50rpx; width: 350rpx;" />
</view>
<view class="row line">
<text style="margin-top: 20rpx; width: 110rpx;">收货地址</text>
<textarea v-model="address" placeholder="" :auto-height="false" :maxlength="-1"
style="height: 50px; width: 350rpx;margin-left: 50rpx;" />
</view>
</view>
<view class="column"
style="width: 550rpx; background-color: white; align-items: center;margin-top: 20rpx;border-radius: 16rpx; padding-bottom: 20rpx;">
<text style="font-size: 25rpx; color: black; margin-top: 40rpx;">产品信息填写</text>
<view class="row line">
<text style="width: 110rpx;">型号</text>
<input v-model="model" type="text" style="margin-left: 50rpx; width: 350rpx;" />
</view>
<view class="row line">
<text style="width: 110rpx;">出品编号</text>
<input v-model="number" type="text" style="margin-left: 50rpx; width: 350rpx;" />
</view>
<view class="row line">
<text style="width: 110rpx;">出品年月</text>
<input v-model="createTime" type="text" style="margin-left: 50rpx; width: 350rpx;" />
</view>
<view class="row" style="width: 100%; margin-top: 40rpx; align-items: flex-start; flex-wrap: wrap;">
<view class="center" @click="seleImg"
style="width: 150rpx; height:150rpx; background-color: gainsboro; margin-left: 30rpx; margin-right: 20rpx; position: relative;">
<text style="position: absolute;">+</text>
</view>
<image style="width: 150rpx; height:150rpx; margin-right: 20rpx;" v-if="imagePath"
:src="imagePath" mode="aspectFit" @click="previewImage">
</image>
</view>
<text style="font-size: 22rpx; margin-top: 20rpx;width: 90%;">拍摄并上传清晰的产品铭牌信息用于辅助审核,通过后立即发货</text>
</view>
<view class="row" style="width: 550rpx; justify-content: space-between; margin-top: 40rpx;">
<view class="center" @click="closeReceivePop"
style="width: 150rpx; height: 80rpx; background-color: #CCCCCC; border-radius: 16rpx;">
<text style="font-size: 28rpx; color: #333;">关闭</text>
</view>
<view class="center" @click="submitForm"
style="width: 350rpx; height: 80rpx; background-color: #0877FF; border-radius: 16rpx;position: relative;">
<text style="font-size: 28rpx; color: white;">提交</text>
</view>
</view>
</view>
</uni-popup>
<!-- 领取记录 -->
<uni-popup ref="recordPop" type="center">
<view class="column"
style="width: 604rpx; height: 598rpx; background-color: #F5F5F5; border-radius: 16rpx; align-items: center;">
<view class="row"
style="width: 90%; justify-content: space-between; align-items: center; margin-top: 30rpx;">
<view class="" style="width: 30rpx;">
</view>
<text style="font-size: 35rpx; font-weight: 600; color: black;">领取记录</text>
<image src="/static/ic_close.png" @click="closeRecordPop()" style="width: 30rpx; height: 30rpx;"
mode=""></image>
</view>
<view class="column"
style="width: 100%; height: 460rpx; margin-top: 30rpx; overflow-y: auto; font-size: 25rpx; align-items: center;">
<view class="column" v-for="item in recordList" :key="item.phone + item.time"
style="width: 90%; height: 180rpx; margin-bottom: 10rpx; position: relative; background-color: white; padding: 10rpx; border-radius: 16rpx;">
<view class="row" style="justify-content: space-between; margin-top: 20rpx;">
<view class="row">
<text>{{ item.name }}</text>
<text style="margin-left: 20rpx;">{{ item.phone }}</text>
</view>
<text>{{ item.time }}</text>
</view>
<text style="margin-top: 20rpx;">{{ item.address }}</text>
</view>
</view>
</view>
</uni-popup>
</view>
</template>
<script>
import uniNoticeBar from '@/uni_modules/uni-notice-bar/components/uni-notice-bar/uni-notice-bar.vue'
import {
processImage
} from '@/common/utils'
export default {
components: {
uniNoticeBar
},
onLoad() {
this.getConfig();
var userId = uni.getStorageSync("user_id");
if (!userId || userId == 0) {
this.login();
}
this.userId = userId;
},
data() {
return {
bg: "",
userId: 0,
imagePath: '',
name: "",
phone: "",
base64: "",
workUnit: "",
address: "",
createTime: "",
number: "",
model: "",
recordList: [],
// 图片数据
imageList: [{
url: 'https://picsum.photos/300/200?random=1',
alt: '图片1'
},
{
url: 'https://picsum.photos/300/200?random=2',
alt: '图片2'
},
{
url: 'https://picsum.photos/300/200?random=3',
alt: '图片3'
},
{
url: 'https://picsum.photos/300/200?random=4',
alt: '图片4'
},
{
url: 'https://picsum.photos/300/200?random=5',
alt: '图片5'
},
{
url: 'https://picsum.photos/300/200?random=6',
alt: '图片6'
}
],
scrollTimer: null, // 滚动定时器
scrollSpeed: 1, // 滚动速度 (px/帧)
translateX: 0, // 位移量
listWidth: 0, // 列表宽度
isScrolling: false // 是否正在滚动
}
},
onReady() {
// 获取列表宽度
this.$nextTick(() => {
const query = uni.createSelectorQuery().in(this);
query.select('.image-list').boundingClientRect(data => {
this.listWidth = data.width;
// 开始自动滚动
this.startAutoScroll();
}).exec();
});
},
onUnload() {
// 页面卸载时清除定时器
this.stopAutoScroll();
},
methods: {
request(url, method, data) {
return new Promise((resolve, reject) => {
const header = {
};
if (method == "post") {
header['content-type'] = 'application/json';
}
uni.request({
url: "https://gift.zpc-xy.com/" + url,
method: method,
data: data,
header: header,
timeout: 10000,
success: (res) => {
console.log('API响应:', res);
if (res.statusCode === 200) {
resolve(res.data);
} else {
reject(new Error(`请求失败,状态码: ${res.statusCode}`));
}
},
fail: (err) => {
console.error('API请求失败:', err);
reject(err);
}
});
})
},
async getConfig() {
const res = await this.request("config", "get", {});
console.log(res);
if (res.home != "") {
this.bg = res.home;
}
},
wxLogin() {
return new Promise((resolve, reject) => {
uni.login({
provider: 'weixin', //使用微信登录
onlyAuthorize: true,
success: async function (res) {
// if()
resolve(res.code);
},
fail: function (err) {
reject(err);
}
})
})
},
async login() {
try {
const wxCode = await this.wxLogin();
if (wxCode) {
const res = await this.request("userLogin?code=" + wxCode, "post", {});
if (res.code == 200) {
uni.setStorageSync("user_id", res.data.user_id);
this.userId = res.data.user_id;
console.log('登录成功, userId:', this.userId);
} else {
console.error('登录失败:', res.message);
}
}
} catch (error) {
console.error('登录过程出错:', error);
}
},
openReceivePop() {
this.$refs.receivePop.open();
},
closeReceivePop() {
this.$refs.receivePop.close();
},
getUserId() {
if (this.userId == 0) {
var userId = uni.getStorageSync("user_id");
if (!userId || userId == 0) {
this.login();
} else {
this.userId = userId;
}
}
return this.userId;
},
async openRecordPop() {
await this.loadRecordList();
this.$refs.recordPop.open();
},
async loadRecordList() {
try {
uni.showLoading({
title: '加载中...'
});
// 这里可以调用API获取实际的领取记录
const result = await this.request('getRecord?userId=' + this.getUserId(), 'GET', {});
console.log(result);
if (result.data.length > 0) {
let isShow = true;
let record = [];
for (var index = 0; index < result.data.length; index++) {
var element = result.data[index];
if (element.status == 1) {
record.push(element)
}
}
this.recordList = record;
}
// 目前使用模拟数据
console.log('加载领取记录...');
} catch (error) {
console.error('加载领取记录失败:', error);
}
uni.hideLoading();
},
closeRecordPop() {
this.$refs.recordPop.close();
},
async seleImg() {
try {
uni.showLoading({
title: '处理中...'
});
const {
base64,
path
} = await processImage();
console.log('最终Base64长度:', base64.length, path);
this.imagePath = path;
this.base64 = base64;
uni.showToast({
title: '上传成功'
});
} catch (err) {
console.error('处理失败', err);
uni.showToast({
title: '处理失败',
icon: 'none'
});
} finally {
uni.hideLoading();
}
},
validateForm() {
if (!this.name.trim()) {
uni.showToast({
title: '请填写姓名',
icon: 'none'
});
return false;
}
if (!this.phone.trim()) {
uni.showToast({
title: '请填写联系方式',
icon: 'none'
});
return false;
}
if (!this.workUnit.trim()) {
uni.showToast({
title: '请填写工作单位',
icon: 'none'
});
return false;
}
if (!this.address.trim()) {
uni.showToast({
title: '请填写收货地址',
icon: 'none'
});
return false;
}
if (!this.model.trim()) {
uni.showToast({
title: '请填写设备型号',
icon: 'none'
});
return false;
}
if (!this.number.trim()) {
uni.showToast({
title: '请填写出品编号',
icon: 'none'
});
return false;
}
if (!this.createTime.trim()) {
uni.showToast({
title: '请填写出品年月',
icon: 'none'
});
return false;
}
if (!this.imagePath) {
uni.showToast({
title: '请上传产品铭牌照片',
icon: 'none'
});
return false;
}
return true;
},
async submitForm() {
if (!this.validateForm()) {
return;
}
uni.showLoading({
title: '提交中...'
});
try {
const formData = {
UserId: this.userId,
Name: this.name,
Phone: this.phone,
Company: this.workUnit,
Address: this.address,
ProductModel: this.model,
ProductSerialNumber: this.number,
ProductDate: this.createTime,
ProductImage: this.base64
};
// 这里可以调用API提交数据
const result = await this.request('addRecord', 'POST', formData);
console.log(result);
uni.hideLoading();
if (result.code == 200) {
uni.showToast({
title: '提交成功,请等待审核',
icon: 'success'
});
this.closeReceivePop();
this.clearForm();
} else {
uni.showToast({
title: '提交失败,请重试',
icon: 'none'
});
}
} catch (error) {
uni.hideLoading();
uni.showToast({
title: '提交失败,请重试',
icon: 'none'
});
console.error('提交失败:', error);
}
},
clearForm() {
this.name = '';
this.phone = '';
this.workUnit = '';
this.address = '';
this.model = '';
this.number = '';
this.createTime = '';
this.imagePath = '';
this.base64 = '';
},
previewImage() {
if (this.imagePath) {
uni.previewImage({
current: this.imagePath,
urls: [this.imagePath],
success: function(res) {
console.log('预览图片成功');
},
fail: function(err) {
console.error('预览图片失败:', err);
uni.showToast({
title: '预览失败',
icon: 'none'
});
}
});
}
},
// 开始自动滚动
startAutoScroll() {
this.stopAutoScroll(); // 先清除已有定时器
// 每16ms滚动一次 (约60帧/秒)
this.scrollTimer = setInterval(() => {
this.translateX -= this.scrollSpeed;
// 当滚动距离达到一个列表宽度时,重置位置实现无缝滚动
if (Math.abs(this.translateX) >= this.listWidth) {
this.translateX = 0;
}
this.isScrolling = true;
}, 16);
},
// 停止自动滚动
stopAutoScroll() {
if (this.scrollTimer) {
clearInterval(this.scrollTimer);
this.scrollTimer = null;
this.isScrolling = false;
}
},
// 监听滚动事件 (用于鼠标悬停暂停)
onScroll() {
// 可以在这里处理手动滚动后的逻辑
}
}
}
</script>
<style scoped>
.content {
width: 100%;
height: 100vh;
display: flex;
flex-direction: column;
align-items: center;
justify-content: center;
position: relative;
}
.line {
width: 90%;
justify-content: center;
margin-top: 20rpx;
border-bottom: 0.86px solid #e3e3e3;
}
.auto-scroll-container {
width: 100%;
overflow: hidden;
/* 隐藏滚动条 */
padding: 20rpx 0;
}
.scroll-view {
width: 100%;
white-space: nowrap;
/* 防止换行 */
}
.scroll-content {
display: flex;
}
.image-list {
display: flex;
flex-direction: row;
}
.image-item {
width: 240rpx;
height: 200rpx;
margin-right: 20rpx;
border-radius: 8rpx;
overflow: hidden;
}
.item-image {
width: 100%;
height: 100%;
display: block;
}
</style>