221 lines
5.1 KiB
Vue
221 lines
5.1 KiB
Vue
<template>
|
|
<!-- 模板部分保持不变 -->
|
|
<view class="container">
|
|
<canvas
|
|
type="2d"
|
|
id="seatCanvas"
|
|
class="canvas"
|
|
@touchstart="handleTouchStart"
|
|
@touchmove="handleTouchMove"
|
|
@touchend="handleTouchEnd"
|
|
></canvas>
|
|
<view class="controls">
|
|
<button @click="zoomIn">放大</button>
|
|
<button @click="zoomOut">缩小</button>
|
|
<button @click="resetView">重置</button>
|
|
</view>
|
|
</view>
|
|
</template>
|
|
|
|
<script>
|
|
export default {
|
|
data() {
|
|
return {
|
|
seatData: {
|
|
"xCoords": [6,7,8,9,10,11,12,13,14,15],
|
|
"yCoords": [6,6,6,6,6,6,6,6,6,6],
|
|
"statuses": [1,1,1,1,1,1,1,1,1,1],
|
|
"levels": ["B","B","B","B","B","B","A","A","A","A"]
|
|
},
|
|
ctx: null,
|
|
canvas: null,
|
|
img: null,
|
|
scale: 1.0,
|
|
offsetX: 0,
|
|
offsetY: 0,
|
|
lastTouch: { x: 0, y: 0 }
|
|
};
|
|
},
|
|
onReady() {
|
|
this.initCanvas();
|
|
},
|
|
methods: {
|
|
async initCanvas() {
|
|
const query = uni.createSelectorQuery().in(this);
|
|
query.select('#seatCanvas')
|
|
.fields({ node: true, size: true })
|
|
.exec(async (res) => {
|
|
if (!res || !res[0]) return;
|
|
|
|
const canvas = res[0].node;
|
|
const ctx = canvas.getContext('2d');
|
|
const dpr = uni.getSystemInfoSync().pixelRatio;
|
|
|
|
canvas.width = res[0].width * dpr;
|
|
canvas.height = res[0].height * dpr;
|
|
ctx.scale(dpr, dpr);
|
|
|
|
this.canvas = canvas;
|
|
this.ctx = ctx;
|
|
|
|
// 加载座位图片
|
|
try {
|
|
const imagePath = await this.loadImageForMiniProgram(
|
|
'https://assets.tech.troyrc.com/sx25/images/events/dingwei1.png'
|
|
);
|
|
this.img = imagePath;
|
|
this.renderSeats();
|
|
} catch (error) {
|
|
console.error('图片加载失败:', error);
|
|
}
|
|
});
|
|
},
|
|
|
|
// 专为微信小程序优化的图片加载方法
|
|
loadImageForMiniProgram(url) {
|
|
return new Promise((resolve, reject) => {
|
|
// 第一步:下载图片到临时文件
|
|
uni.downloadFile({
|
|
url,
|
|
success: downloadRes => {
|
|
// 第二步:获取图片信息(宽高等)
|
|
uni.getImageInfo({
|
|
src: downloadRes.tempFilePath,
|
|
success: imageInfo => {
|
|
resolve({
|
|
path: downloadRes.tempFilePath,
|
|
width: imageInfo.width,
|
|
height: imageInfo.height
|
|
});
|
|
},
|
|
fail: err => reject(`获取图片信息失败: ${JSON.stringify(err)}`)
|
|
});
|
|
},
|
|
fail: err => reject(`下载图片失败: ${JSON.stringify(err)}`)
|
|
});
|
|
});
|
|
},
|
|
|
|
renderSeats() {
|
|
if (!this.ctx || !this.img) return;
|
|
|
|
const { ctx } = this;
|
|
const GRID_SIZE = 30 * this.scale;
|
|
|
|
// 清空画布
|
|
ctx.clearRect(0, 0, this.canvas.width, this.canvas.height);
|
|
|
|
// 绘制所有座位
|
|
this.seatData.xCoords.forEach((x, i) => {
|
|
const y = this.seatData.yCoords[i];
|
|
const status = this.seatData.statuses[i];
|
|
|
|
// 计算实际绘制位置
|
|
const drawX = (x - 6) * GRID_SIZE + this.offsetX;
|
|
const drawY = (y - 6) * GRID_SIZE + this.offsetY;
|
|
|
|
// 绘制座位图片 - 直接使用临时文件路径
|
|
ctx.drawImage(
|
|
this.img.path,
|
|
drawX,
|
|
drawY,
|
|
GRID_SIZE,
|
|
GRID_SIZE
|
|
);
|
|
|
|
// 根据状态添加效果
|
|
if (status === 2) { // 不可用状态
|
|
ctx.fillStyle = 'rgba(0,0,0,0.5)';
|
|
ctx.fillRect(drawX, drawY, GRID_SIZE, GRID_SIZE);
|
|
}
|
|
|
|
// 绘制座位信息
|
|
ctx.fillStyle = '#ffffff';
|
|
ctx.font = `${8 * this.scale}px sans-serif`;
|
|
ctx.textAlign = 'center';
|
|
ctx.fillText(
|
|
`${this.seatData.rowNames[i]}${this.seatData.seatNames[i]}`,
|
|
drawX + GRID_SIZE / 2,
|
|
drawY + GRID_SIZE / 2 + 3 * this.scale
|
|
);
|
|
});
|
|
|
|
// 在微信小程序中必须调用 draw() 方法才能更新画布
|
|
ctx.draw();
|
|
},
|
|
// 手势操作(保持不变)
|
|
handleTouchStart(e) {
|
|
this.lastTouch = {
|
|
x: e.touches[0].x,
|
|
y: e.touches[0].y
|
|
};
|
|
},
|
|
|
|
handleTouchMove(e) {
|
|
const touchX = e.touches[0].x;
|
|
const touchY = e.touches[0].y;
|
|
|
|
this.offsetX += (touchX - this.lastTouch.x) * 1.5;
|
|
this.offsetY += (touchY - this.lastTouch.y) * 1.5;
|
|
|
|
this.lastTouch = { x: touchX, y: touchY };
|
|
this.renderSeats();
|
|
},
|
|
|
|
handleTouchEnd() {
|
|
// 可添加惯性滑动效果
|
|
},
|
|
|
|
// 缩放控制(保持不变)
|
|
zoomIn() {
|
|
this.scale = Math.min(this.scale * 1.2, 3.0);
|
|
this.renderSeats();
|
|
},
|
|
|
|
zoomOut() {
|
|
this.scale = Math.max(this.scale * 0.8, 0.5);
|
|
this.renderSeats();
|
|
},
|
|
|
|
resetView() {
|
|
this.scale = 1.0;
|
|
this.offsetX = 0;
|
|
this.offsetY = 0;
|
|
this.renderSeats();
|
|
}
|
|
}
|
|
};
|
|
</script>
|
|
|
|
<style scoped>
|
|
/* 样式保持不变 */
|
|
.container {
|
|
position: relative;
|
|
width: 100%;
|
|
height: 80vh;
|
|
}
|
|
|
|
.canvas {
|
|
width: 100%;
|
|
height: 100%;
|
|
background-color: #f5f5f5;
|
|
}
|
|
|
|
.controls {
|
|
position: absolute;
|
|
bottom: 20px;
|
|
left: 0;
|
|
right: 0;
|
|
display: flex;
|
|
justify-content: center;
|
|
gap: 15px;
|
|
}
|
|
|
|
.controls button {
|
|
padding: 8px 16px;
|
|
background-color: #4a7afe;
|
|
color: white;
|
|
border-radius: 4px;
|
|
font-size: 14px;
|
|
}
|
|
</style> |