if (typeof Promise !== "undefined" && !Promise.prototype.finally) { Promise.prototype.finally = function(callback) { const promise = this.constructor; return this.then( (value) => promise.resolve(callback()).then(() => value), (reason) => promise.resolve(callback()).then(() => { throw reason; }) ); }; } ; if (typeof uni !== "undefined" && uni && uni.requireGlobal) { const global = uni.requireGlobal(); ArrayBuffer = global.ArrayBuffer; Int8Array = global.Int8Array; Uint8Array = global.Uint8Array; Uint8ClampedArray = global.Uint8ClampedArray; Int16Array = global.Int16Array; Uint16Array = global.Uint16Array; Int32Array = global.Int32Array; Uint32Array = global.Uint32Array; Float32Array = global.Float32Array; Float64Array = global.Float64Array; BigInt64Array = global.BigInt64Array; BigUint64Array = global.BigUint64Array; } ; if (uni.restoreGlobal) { uni.restoreGlobal(Vue, weex, plus, setTimeout, clearTimeout, setInterval, clearInterval); } (function(vue) { "use strict"; function formatAppLog(type, filename, ...args) { if (uni.__log__) { uni.__log__(type, filename, ...args); } else { console[type].apply(console, [...args, filename]); } } const _export_sfc = (sfc, props) => { const target = sfc.__vccOpts || sfc; for (const [key, val] of props) { target[key] = val; } return target; }; const _sfc_main$2 = { data() { return { ctx: null, canvasWidth: 300, canvasHeight: 500, seatSize: 30, gap: 10, rows: 8, cols: 10, seats: [], selectedSeats: [], touchStartX: 0, touchStartY: 0, offsetX: 0, offsetY: 0 }; }, onReady() { this.initSeats(); this.initAndroidCanvas(); }, methods: { initSeats() { for (let i = 0; i < this.rows; i++) { this.seats[i] = []; for (let j = 0; j < this.cols; j++) { const isSold = Math.random() < 0.2; this.seats[i][j] = { row: i, col: j, status: isSold ? "sold" : "available", x: 0, y: 0 }; } } }, // 替换原来的 initAndroidCanvas 方法 initAndroidCanvas() { return new Promise((resolve) => { this.ctx = uni.createCanvasContext("seatCanvas", this); formatAppLog("log", "at pages/index/step2.vue:77", this.ctx, "ctx123123123"); const query = uni.createSelectorQuery().in(this); query.select(".seat-canvas").boundingClientRect((rect) => { if (!rect) { formatAppLog("error", "at pages/index/step2.vue:83", "获取Canvas尺寸失败"); return resolve(false); } this.canvasWidth = rect.width; this.canvasHeight = rect.height; const totalWidth = this.cols * (this.seatSize + this.gap) - this.gap; const totalHeight = this.rows * (this.seatSize + this.gap) - this.gap; this.offsetX = (this.canvasWidth - totalWidth) / 2; this.offsetY = (this.canvasHeight - totalHeight) / 2; this.drawSeats(); resolve(true); }).exec(); }); }, drawSeats() { if (!this.ctx) return; this.ctx.clearRect(0, 0, this.canvasWidth, this.canvasHeight); for (let i = 0; i < this.rows; i++) { for (let j = 0; j < this.cols; j++) { const seat = this.seats[i][j]; const x = j * (this.seatSize + this.gap) + this.offsetX; const y = i * (this.seatSize + this.gap) + this.offsetY; seat.x = x; seat.y = y; switch (seat.status) { case "available": this.ctx.setFillStyle("#4CAF50"); break; case "selected": this.ctx.setFillStyle("#2196F3"); break; case "sold": this.ctx.setFillStyle("#9E9E9E"); break; } this.ctx.fillRect(x, y, this.seatSize, this.seatSize); this.ctx.setFillStyle("#FFFFFF"); this.ctx.setFontSize(12); this.ctx.setTextAlign("center"); this.ctx.fillText( `${String.fromCharCode(65 + i)}${j + 1}`, x + this.seatSize / 2, y + this.seatSize / 2 + 4 // 安卓平台文字垂直对齐需要微调 ); } } this.ctx.draw(); }, // 触摸事件处理(安卓专用优化) handleTouchStart(e) { this.touchStartX = e.touches[0].x; this.touchStartY = e.touches[0].y; }, handleTouchMove(e) { const touchX = e.touches[0].x; const touchY = e.touches[0].y; const dx = touchX - this.touchStartX; const dy = touchY - this.touchStartY; this.offsetX += dx; this.offsetY += dy; const minX = this.canvasWidth - (this.cols * (this.seatSize + this.gap) - this.gap); const minY = this.canvasHeight - (this.rows * (this.seatSize + this.gap) - this.gap); this.offsetX = Math.max(minX, Math.min(0, this.offsetX)); this.offsetY = Math.max(minY, Math.min(0, this.offsetY)); this.touchStartX = touchX; this.touchStartY = touchY; this.drawSeats(); }, handleTouchEnd(e) { const touchX = e.changedTouches[0].x; const touchY = e.changedTouches[0].y; for (let i = 0; i < this.rows; i++) { for (let j = 0; j < this.cols; j++) { const seat = this.seats[i][j]; if (touchX >= seat.x && touchX <= seat.x + this.seatSize && touchY >= seat.y && touchY <= seat.y + this.seatSize) { this.toggleSeatSelection(seat); return; } } } }, toggleSeatSelection(seat) { if (seat.status === "sold") return; if (seat.status === "available") { seat.status = "selected"; this.selectedSeats.push(`${String.fromCharCode(65 + seat.row)}${seat.col + 1}`); } else { seat.status = "available"; this.selectedSeats = this.selectedSeats.filter( (s) => s !== `${String.fromCharCode(65 + seat.row)}${seat.col + 1}` ); } this.drawSeats(); } } }; function _sfc_render$1(_ctx, _cache, $props, $setup, $data, $options) { return vue.openBlock(), vue.createElementBlock("view", { class: "container" }, [ vue.createElementVNode("view", { class: "screen" }, "银幕"), vue.createElementVNode( "canvas", { "canvas-id": "seatCanvas", type: "2d", class: "seat-canvas", onTouchstart: _cache[0] || (_cache[0] = (...args) => $options.handleTouchStart && $options.handleTouchStart(...args)), onTouchmove: _cache[1] || (_cache[1] = (...args) => $options.handleTouchMove && $options.handleTouchMove(...args)), onTouchend: _cache[2] || (_cache[2] = (...args) => $options.handleTouchEnd && $options.handleTouchEnd(...args)) }, null, 32 /* NEED_HYDRATION */ ), vue.createElementVNode("view", { class: "legend" }, [ vue.createElementVNode("view", { class: "legend-item" }, [ vue.createElementVNode("view", { class: "seat-icon available" }), vue.createElementVNode("text", null, "可选") ]), vue.createElementVNode("view", { class: "legend-item" }, [ vue.createElementVNode("view", { class: "seat-icon selected" }), vue.createElementVNode("text", null, "已选") ]), vue.createElementVNode("view", { class: "legend-item" }, [ vue.createElementVNode("view", { class: "seat-icon sold" }), vue.createElementVNode("text", null, "已售") ]) ]), vue.createElementVNode("view", { class: "selected-seats" }, [ vue.createElementVNode( "text", null, "已选座位:" + vue.toDisplayString($data.selectedSeats.join(", ") || "无"), 1 /* TEXT */ ) ]) ]); } const PagesIndexStep2 = /* @__PURE__ */ _export_sfc(_sfc_main$2, [["render", _sfc_render$1], ["__file", "/Users/sunmeng/Desktop/wx/canvas/pages/index/step2.vue"]]); const _sfc_main$1 = { data() { return { ctx: null, canvasWidth: 0, canvasHeight: 0, seatSize: 30, gap: 10, rows: 8, cols: 10, seats: [], selectedSeats: [], touchStartX: 0, touchStartY: 0, offsetX: 0, offsetY: 0, scale: 1 }; }, onReady() { this.initSeats(); this.initCanvas(); }, methods: { initSeats() { for (let i = 0; i < this.rows; i++) { this.seats[i] = []; for (let j = 0; j < this.cols; j++) { const isSold = Math.random() < 0.2; this.seats[i][j] = { row: i, col: j, status: isSold ? "sold" : "available", // available, selected, sold x: 0, y: 0 }; } } }, async initCanvas() { const { canvas, width, height } = await this.getCanvasNode("seatCanvas"); this.canvasWidth = width; this.canvasHeight = height; this.ctx = canvas.getContext("2d"); const totalWidth = this.cols * (this.seatSize + this.gap) - this.gap; const totalHeight = this.rows * (this.seatSize + this.gap) - this.gap; this.offsetX = (this.canvasWidth - totalWidth) / 2; this.offsetY = (this.canvasHeight - totalHeight) / 2; this.drawSeats(); }, getCanvasNode(id) { return new Promise((resolve) => { const query = uni.createSelectorQuery().in(this); query.select(`#${id}`).fields({ node: true, size: true }).exec((res) => { formatAppLog("log", "at pages/index/index.vue:94", "给我看看", res); formatAppLog("log", "at pages/index/index.vue:95", "给我看看", res); formatAppLog("log", "at pages/index/index.vue:96", "给我看看", res); formatAppLog("log", "at pages/index/index.vue:97", "给我看看", res); formatAppLog("log", "at pages/index/index.vue:98", "给我看看", res); formatAppLog("log", "at pages/index/index.vue:99", "给我看看", res); const canvas = res[0].node; const width = res[0].width; const height = res[0].height; canvas.width = width * uni.getSystemInfoSync().pixelRatio; canvas.height = height * uni.getSystemInfoSync().pixelRatio; resolve({ canvas, width, height }); }); }); }, drawSeats() { if (!this.ctx) return; this.ctx.clearRect(0, 0, this.canvasWidth, this.canvasHeight); this.ctx.save(); this.ctx.translate(this.offsetX, this.offsetY); this.ctx.scale(this.scale, this.scale); for (let i = 0; i < this.rows; i++) { for (let j = 0; j < this.cols; j++) { const seat = this.seats[i][j]; const x = j * (this.seatSize + this.gap); const y = i * (this.seatSize + this.gap); seat.x = x; seat.y = y; switch (seat.status) { case "available": this.ctx.fillStyle = "#4CAF50"; break; case "selected": this.ctx.fillStyle = "#2196F3"; break; case "sold": this.ctx.fillStyle = "#9E9E9E"; break; } this.ctx.beginPath(); this.ctx.roundRect(x, y, this.seatSize, this.seatSize, 4); this.ctx.fill(); this.ctx.fillStyle = "#FFFFFF"; this.ctx.font = "12px Arial"; this.ctx.textAlign = "center"; this.ctx.textBaseline = "middle"; this.ctx.fillText( `${String.fromCharCode(65 + i)}${j + 1}`, x + this.seatSize / 2, y + this.seatSize / 2 ); } } this.ctx.restore(); }, handleTouchStart(e) { this.touchStartX = e.touches[0].x; this.touchStartY = e.touches[0].y; }, handleTouchMove(e) { const touchX = e.touches[0].x; const touchY = e.touches[0].y; const dx = touchX - this.touchStartX; const dy = touchY - this.touchStartY; this.offsetX += dx; this.offsetY += dy; const minX = this.canvasWidth - (this.cols * (this.seatSize + this.gap) - this.gap) * this.scale; const minY = this.canvasHeight - (this.rows * (this.seatSize + this.gap) - this.gap) * this.scale; this.offsetX = Math.max(minX, Math.min(0, this.offsetX)); this.offsetY = Math.max(minY, Math.min(0, this.offsetY)); this.touchStartX = touchX; this.touchStartY = touchY; this.drawSeats(); }, handleTouchEnd(e) { const touchX = e.changedTouches[0].x; const touchY = e.changedTouches[0].y; const canvasX = (touchX - this.offsetX) / this.scale; const canvasY = (touchY - this.offsetY) / this.scale; for (let i = 0; i < this.rows; i++) { for (let j = 0; j < this.cols; j++) { const seat = this.seats[i][j]; if (canvasX >= seat.x && canvasX <= seat.x + this.seatSize && canvasY >= seat.y && canvasY <= seat.y + this.seatSize) { this.toggleSeatSelection(seat); return; } } } }, toggleSeatSelection(seat) { if (seat.status === "sold") return; if (seat.status === "available") { seat.status = "selected"; this.selectedSeats.push(`${String.fromCharCode(65 + seat.row)}${seat.col + 1}`); } else { seat.status = "available"; this.selectedSeats = this.selectedSeats.filter( (s) => s !== `${String.fromCharCode(65 + seat.row)}${seat.col + 1}` ); } this.drawSeats(); } } }; function _sfc_render(_ctx, _cache, $props, $setup, $data, $options) { return vue.openBlock(), vue.createElementBlock("view", { class: "container" }, [ vue.createElementVNode("view", { class: "screen" }, "银幕"), vue.createElementVNode( "canvas", { "canvas-id": "seatCanvas", type: "2d", class: "seat-canvas", onTouchstart: _cache[0] || (_cache[0] = (...args) => $options.handleTouchStart && $options.handleTouchStart(...args)), onTouchmove: _cache[1] || (_cache[1] = (...args) => $options.handleTouchMove && $options.handleTouchMove(...args)), onTouchend: _cache[2] || (_cache[2] = (...args) => $options.handleTouchEnd && $options.handleTouchEnd(...args)) }, null, 32 /* NEED_HYDRATION */ ), vue.createElementVNode("view", { class: "legend" }, [ vue.createElementVNode("view", { class: "legend-item" }, [ vue.createElementVNode("view", { class: "seat-icon available" }), vue.createElementVNode("text", null, "可选") ]), vue.createElementVNode("view", { class: "legend-item" }, [ vue.createElementVNode("view", { class: "seat-icon selected" }), vue.createElementVNode("text", null, "已选") ]), vue.createElementVNode("view", { class: "legend-item" }, [ vue.createElementVNode("view", { class: "seat-icon sold" }), vue.createElementVNode("text", null, "已售") ]) ]), vue.createElementVNode("view", { class: "selected-seats" }, [ vue.createElementVNode( "text", null, "已选座位:" + vue.toDisplayString($data.selectedSeats.join(", ") || "无"), 1 /* TEXT */ ) ]) ]); } const PagesIndexIndex = /* @__PURE__ */ _export_sfc(_sfc_main$1, [["render", _sfc_render], ["__file", "/Users/sunmeng/Desktop/wx/canvas/pages/index/index.vue"]]); __definePage("pages/index/step2", PagesIndexStep2); __definePage("pages/index/index", PagesIndexIndex); const _sfc_main = { onLaunch: function() { formatAppLog("log", "at App.vue:4", "App Launch"); }, onShow: function() { formatAppLog("log", "at App.vue:7", "App Show"); }, onHide: function() { formatAppLog("log", "at App.vue:10", "App Hide"); } }; const App = /* @__PURE__ */ _export_sfc(_sfc_main, [["__file", "/Users/sunmeng/Desktop/wx/canvas/App.vue"]]); function createApp() { const app = vue.createVueApp(App); return { app }; } const { app: __app__, Vuex: __Vuex__, Pinia: __Pinia__ } = createApp(); uni.Vuex = __Vuex__; uni.Pinia = __Pinia__; __app__.provide("__globalStyles", __uniConfig.styles); __app__._component.mpType = "app"; __app__._component.render = () => { }; __app__.mount("#app"); })(Vue);