fix(special-zone): 修复白名单弹窗checkbox未显示问题并添加专区小程序码功能
- 修复 UserSelectModal 弹窗中复选框不显示的根因,正确传入 selection-type="checkbox" - 新增后台接口获取专区小程序码图片流,支持正式/体验/开发版环境 - 管理后台专区列表新增二维码按钮,弹窗展示对应专区小程序码 - 小程序端支持扫码参数 scene 解析,实现扫码直接进入专区页面 - 优化二维码弹窗组件,支持切换小程序版本并动态加载二维码 - 重新构建前端及后端服务,确保新功能生效和兼容原有业务逻辑
This commit is contained in:
@@ -182,3 +182,31 @@ export async function checkSectionPermission(sectionIds: number[]) {
|
||||
}
|
||||
return Promise.reject(new Error(res.data.message));
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取专区小程序码(图片流),返回可用于 <img src> 的 objectURL
|
||||
* @param id 专区ID
|
||||
* @param envVersion release(正式版) / trial(体验版) / develop(开发版)
|
||||
*/
|
||||
export async function getSectionQrcode(
|
||||
id: number,
|
||||
envVersion: string = 'release'
|
||||
): Promise<string> {
|
||||
const res = await request.get(
|
||||
MODULES_API_URL + '/shop/shop-home-section/' + id + '/qrcode',
|
||||
{ responseType: 'blob', params: { envVersion } } as any
|
||||
);
|
||||
const blob = res.data as Blob;
|
||||
// 微信/后端出错时会返回 JSON 而非图片,这里解析出错误信息
|
||||
if (blob && blob.type && blob.type.indexOf('image') === -1) {
|
||||
let msg = '生成小程序码失败';
|
||||
try {
|
||||
const json = JSON.parse(await blob.text());
|
||||
if (json && json.error) msg = json.error;
|
||||
} catch (e) {
|
||||
/* 忽略解析失败 */
|
||||
}
|
||||
return Promise.reject(new Error(msg));
|
||||
}
|
||||
return window.URL.createObjectURL(blob);
|
||||
}
|
||||
|
||||
@@ -15,6 +15,7 @@
|
||||
:datasource="datasource"
|
||||
:columns="columns"
|
||||
:row-selection="rowSelection"
|
||||
selection-type="checkbox"
|
||||
:pagination="true"
|
||||
:page-size="10"
|
||||
>
|
||||
|
||||
@@ -69,6 +69,8 @@
|
||||
<a-divider type="vertical" />
|
||||
<a @click="openGoods(record)">商品</a>
|
||||
<a-divider type="vertical" />
|
||||
<a @click="openQrcode(record)">二维码</a>
|
||||
<a-divider type="vertical" />
|
||||
<a-popconfirm
|
||||
title="确定要删除此专区吗?"
|
||||
@confirm="remove(record)"
|
||||
@@ -175,6 +177,39 @@
|
||||
</a-table>
|
||||
</a-spin>
|
||||
</a-drawer>
|
||||
|
||||
<!-- 专区小程序码弹窗 -->
|
||||
<a-modal
|
||||
:visible="showQrcode"
|
||||
:title="qrcodeTitle"
|
||||
:footer="null"
|
||||
:width="360"
|
||||
:maskClosable="false"
|
||||
@update:visible="closeQrcode"
|
||||
>
|
||||
<div style="text-align: center; padding: 8px 0 4px;">
|
||||
<div style="margin-bottom: 10px;">
|
||||
<a-radio-group v-model:value="qrcodeEnv" size="small" @change="onQrcodeEnvChange">
|
||||
<a-radio-button value="release">正式版</a-radio-button>
|
||||
<a-radio-button value="trial">体验版</a-radio-button>
|
||||
<a-radio-button value="develop">开发版</a-radio-button>
|
||||
</a-radio-group>
|
||||
</div>
|
||||
<a-spin :spinning="qrcodeLoading">
|
||||
<img
|
||||
v-if="qrcodeUrl"
|
||||
:src="qrcodeUrl"
|
||||
style="width: 240px; height: 240px; object-fit: contain; border: 1px solid #f0f0f0; border-radius: 8px;"
|
||||
/>
|
||||
<div v-else style="width: 240px; height: 240px; line-height: 240px; color: #999;">
|
||||
加载中...
|
||||
</div>
|
||||
</a-spin>
|
||||
<div style="margin-top: 12px; font-size: 13px; color: #888;">
|
||||
微信扫一扫,直接进入该专区
|
||||
</div>
|
||||
</div>
|
||||
</a-modal>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
@@ -199,7 +234,8 @@
|
||||
setSectionUsers,
|
||||
listSectionGoods,
|
||||
addSectionGoods,
|
||||
removeSectionGoods
|
||||
removeSectionGoods,
|
||||
getSectionQrcode
|
||||
} from '@/api/shop/shopZone';
|
||||
import { pageShopGoods } from '@/api/shop/shopGoods';
|
||||
import type {
|
||||
@@ -231,6 +267,14 @@
|
||||
const goodsSearchLoading = ref(false);
|
||||
const candidateGoods = ref<any[]>([]);
|
||||
|
||||
// 专区小程序码弹窗
|
||||
const showQrcode = ref(false);
|
||||
const qrcodeLoading = ref(false);
|
||||
const qrcodeUrl = ref('');
|
||||
const qrcodeTitle = ref('专区小程序码');
|
||||
const qrcodeEnv = ref('release'); // release(正式版) / trial(体验版) / develop(开发版)
|
||||
const qrcodeSectionId = ref(0);
|
||||
|
||||
// 表格数据源
|
||||
const datasource: DatasourceFunction = ({ page, limit, where, orders }) => {
|
||||
return pageHomeSections({
|
||||
@@ -300,7 +344,7 @@
|
||||
{
|
||||
title: '操作',
|
||||
key: 'action',
|
||||
width: 220,
|
||||
width: 290,
|
||||
fixed: 'right',
|
||||
align: 'center',
|
||||
hideInSetting: true
|
||||
@@ -408,6 +452,53 @@
|
||||
loadGoods(row.sectionId || 0);
|
||||
};
|
||||
|
||||
/* 生成专区小程序码(按当前选择的版本) */
|
||||
const genQrcode = (id: number) => {
|
||||
qrcodeUrl.value = '';
|
||||
qrcodeLoading.value = true;
|
||||
getSectionQrcode(id, qrcodeEnv.value)
|
||||
.then((url) => {
|
||||
qrcodeUrl.value = url;
|
||||
})
|
||||
.catch((e) => {
|
||||
message.error(e?.message || '生成小程序码失败');
|
||||
showQrcode.value = false;
|
||||
})
|
||||
.finally(() => {
|
||||
qrcodeLoading.value = false;
|
||||
});
|
||||
};
|
||||
|
||||
/* 打开专区小程序码弹窗 */
|
||||
const openQrcode = (row: HomeSection) => {
|
||||
const id = row.sectionId || 0;
|
||||
qrcodeSectionId.value = id;
|
||||
qrcodeTitle.value = '专区小程序码 - ' + (row.title || id);
|
||||
if (qrcodeUrl.value) {
|
||||
window.URL.revokeObjectURL(qrcodeUrl.value);
|
||||
qrcodeUrl.value = '';
|
||||
}
|
||||
qrcodeLoading.value = true;
|
||||
showQrcode.value = true;
|
||||
genQrcode(id);
|
||||
};
|
||||
|
||||
/* 切换小程序版本后重新生成 */
|
||||
const onQrcodeEnvChange = () => {
|
||||
if (qrcodeSectionId.value && showQrcode.value) {
|
||||
genQrcode(qrcodeSectionId.value);
|
||||
}
|
||||
};
|
||||
|
||||
/* 关闭专区小程序码弹窗并回收资源 */
|
||||
const closeQrcode = (v: boolean) => {
|
||||
showQrcode.value = v;
|
||||
if (!v && qrcodeUrl.value) {
|
||||
window.URL.revokeObjectURL(qrcodeUrl.value);
|
||||
qrcodeUrl.value = '';
|
||||
}
|
||||
};
|
||||
|
||||
const loadGoods = (sectionId: number) => {
|
||||
goodsLoading.value = true;
|
||||
listSectionGoods(sectionId, { page: goodsPage.value, limit: 10 })
|
||||
|
||||
Reference in New Issue
Block a user