This commit is contained in:
2025-09-17 14:40:16 +08:00
parent 46c5682960
commit a3bbc0098a
94 changed files with 3549 additions and 105 deletions

View File

@@ -0,0 +1,144 @@
"use strict";
const common_vendor = require("../common/vendor.js");
const common_http = require("../common/http.js");
const ITEM_SIZE = 210;
const GAP = 18;
const COLS = 3;
function px(rpx) {
return rpx;
}
const _sfc_main = {
name: "ImageUploader",
props: {
modelValue: { type: Array, default: () => [] },
max: { type: Number, default: 9 },
uploadPath: { type: String, default: "/api/attachments" },
uploadFieldName: { type: String, default: "file" },
formData: { type: Object, default: () => ({ ownerType: "product" }) }
},
data() {
return {
innerList: []
};
},
computed: {
areaHeight() {
const rows = Math.ceil((this.innerList.length + 1) / COLS) || 1;
return rows * ITEM_SIZE + (rows - 1) * GAP;
}
},
watch: {
modelValue: {
immediate: true,
handler(list) {
const mapped = (list || []).map((u, i) => ({
uid: String(i) + "_" + (u.id || u.url || Math.random().toString(36).slice(2)),
url: typeof u === "string" ? u : u.url || "",
x: this.posOf(i).x,
y: this.posOf(i).y
}));
this.innerList = mapped;
}
}
},
methods: {
posOf(index) {
const row = Math.floor(index / COLS);
const col = index % COLS;
return { x: px(col * (ITEM_SIZE + GAP)), y: px(row * (ITEM_SIZE + GAP)) };
},
cellStyle(index) {
return {
width: ITEM_SIZE + "rpx",
height: ITEM_SIZE + "rpx"
};
},
preview(index) {
common_vendor.index.previewImage({ urls: this.innerList.map((i) => i.url), current: index });
},
remove(index) {
this.innerList.splice(index, 1);
this.reflow();
this.emit();
},
choose() {
const remain = this.max - this.innerList.length;
if (remain <= 0)
return;
common_vendor.index.chooseImage({ count: remain, success: async (res) => {
for (const path of res.tempFilePaths) {
await this.doUpload(path);
}
} });
},
async doUpload(filePath) {
var _a;
try {
const resp = await common_http.upload(this.uploadPath, filePath, this.formData, this.uploadFieldName);
const url = (resp == null ? void 0 : resp.url) || ((_a = resp == null ? void 0 : resp.data) == null ? void 0 : _a.url) || (resp == null ? void 0 : resp.path) || "";
if (!url)
throw new Error("上传响应无 url");
this.innerList.push({ uid: Math.random().toString(36).slice(2), url, ...this.posOf(this.innerList.length) });
this.reflow();
this.emit();
} catch (e) {
common_vendor.index.showToast({ title: "上传失败", icon: "none" });
}
},
onMoving(index, e) {
const { x, y } = e.detail;
this.innerList[index].x = x;
this.innerList[index].y = y;
},
onMoveEnd(index) {
const mv = this.innerList[index];
const col = Math.round(mv.x / (ITEM_SIZE + GAP));
const row = Math.round(mv.y / (ITEM_SIZE + GAP));
let newIndex = row * COLS + col;
newIndex = Math.max(0, Math.min(newIndex, this.innerList.length - 1));
if (newIndex !== index) {
const moved = this.innerList.splice(index, 1)[0];
this.innerList.splice(newIndex, 0, moved);
}
this.reflow();
this.emit();
},
reflow() {
this.innerList.forEach((it, i) => {
const p = this.posOf(i);
it.x = p.x;
it.y = p.y;
});
},
emit() {
this.$emit("update:modelValue", this.innerList.map((i) => i.url));
this.$emit("change", this.innerList.map((i) => i.url));
}
}
};
function _sfc_render(_ctx, _cache, $props, $setup, $data, $options) {
return common_vendor.e({
a: common_vendor.f($data.innerList, (img, index, i0) => {
return {
a: img.url,
b: common_vendor.o(($event) => $options.preview(index), img.uid),
c: common_vendor.o(($event) => $options.remove(index), img.uid),
d: img.uid,
e: common_vendor.s($options.cellStyle(index)),
f: img.x,
g: img.y,
h: common_vendor.o(($event) => $options.onMoving(index, $event), img.uid),
i: common_vendor.o(($event) => $options.onMoveEnd(index), img.uid)
};
}),
b: $data.innerList.length < $props.max
}, $data.innerList.length < $props.max ? {
c: common_vendor.o((...args) => $options.choose && $options.choose(...args))
} : {}, {
d: $options.areaHeight + "rpx",
e: $options.areaHeight + "rpx"
});
}
const Component = /* @__PURE__ */ common_vendor._export_sfc(_sfc_main, [["render", _sfc_render]]);
wx.createComponent(Component);
//# sourceMappingURL=../../.sourcemap/mp-weixin/components/ImageUploader.js.map

View File

@@ -0,0 +1,4 @@
{
"component": true,
"usingComponents": {}
}

View File

@@ -0,0 +1 @@
<view class="uploader"><view class="grid" style="{{'height:' + e}}"><movable-area class="area" style="{{'height:' + d}}"><movable-view wx:for="{{a}}" wx:for-item="img" wx:key="d" class="cell" style="{{img.e}}" direction="{{'all'}}" damping="{{40}}" friction="{{2}}" x="{{img.f}}" y="{{img.g}}" bindchange="{{img.h}}" bindtouchend="{{img.i}}"><image src="{{img.a}}" mode="aspectFill" class="thumb" bindtap="{{img.b}}"/><view class="remove" catchtap="{{img.c}}">×</view></movable-view><view wx:if="{{b}}" class="adder" bindtap="{{c}}"><text></text></view></movable-area></view></view>

View File

@@ -0,0 +1,15 @@
.uploader { padding: 12rpx; background: #fff;
}
.grid { position: relative;
}
.area { width: 100%; position: relative;
}
.cell { position: absolute; border-radius: 12rpx; overflow: hidden; box-shadow: 0 0 1rpx rgba(0,0,0,0.08);
}
.thumb { width: 100%; height: 100%;
}
.remove { position: absolute; right: 6rpx; top: 6rpx; background: rgba(0,0,0,0.45); color: #fff; width: 40rpx; height: 40rpx; text-align: center; line-height: 40rpx; border-radius: 20rpx; font-size: 28rpx;
}
.adder { width: 210rpx; height: 210rpx; border: 2rpx dashed #ccc; border-radius: 12rpx; display: flex; align-items: center; justify-content: center; color: #999; position: absolute; left: 0; top: 0;
}