Merge branch 'dev' of codeup.aliyun.com:61c14a7efa282c88e103c23f/oak-general-business into dev

This commit is contained in:
Xu Chang 2023-09-22 18:52:31 +08:00
commit 2d732106cd
231 changed files with 14379 additions and 56 deletions

View File

@ -105,5 +105,50 @@ export type GeneralAspectDict<ED extends EntityDict, Cxt extends BackendRuntimeC
result: string;
times?: number;
}>;
getCurrentMenu: (params: {
applicationId: string;
}, context: Cxt) => Promise<any>;
getMenu: (params: {
applicationId: string;
}, context: Cxt) => Promise<any>;
createMenu: (params: {
applicationId: string;
menuConfig: any;
}, context: Cxt) => Promise<any>;
createConditionalMenu: (params: {
applicationId: string;
menuConfig: any;
}, context: Cxt) => Promise<any>;
deleteConditionalMenu: (params: {
applicationId: string;
menuid: number;
}, context: Cxt) => Promise<any>;
batchGetArticle: (params: {
applicationId: string;
offset?: number;
count: number;
noContent?: 0 | 1;
}, context: Cxt) => Promise<any>;
getArticle: (params: {
applicationId: string;
article_id: string;
}, context: Cxt) => Promise<any>;
createMaterial: (params: {
applicationId: string;
type: 'image' | 'voice' | 'video' | 'thumb';
media: FormData;
description?: FormData;
}, context: Cxt) => Promise<any>;
batchGetMaterialList: (params: {
applicationId: string;
type: 'image' | 'video' | 'voice' | 'news';
offset?: number;
count: number;
}, context: Cxt) => Promise<any>;
getMaterial: (params: {
applicationId: string;
type: 'image' | 'video' | 'voice' | 'news';
media_id: string;
}, context: Cxt) => Promise<any>;
};
export default GeneralAspectDict;

11
es/aspects/index.d.ts vendored
View File

@ -7,6 +7,7 @@ import { createWechatLogin } from './wechatLogin';
import { unbindingWechat } from './wechatUser';
import { getMpUnlimitWxaCode } from './wechatQrCode';
import { confirmUserEntityGrant } from './userEntityGrant';
import { getCurrentMenu, getMenu, createMenu, createConditionalMenu, deleteConditionalMenu, batchGetArticle, getArticle, createMaterial, batchGetMaterialList, getMaterial } from './wechatMenu';
declare const aspectDict: {
mergeUser: typeof mergeUser;
switchTo: typeof switchTo;
@ -31,5 +32,15 @@ declare const aspectDict: {
updateUserPassword: typeof updateUserPassword;
getMpUnlimitWxaCode: typeof getMpUnlimitWxaCode;
confirmUserEntityGrant: typeof confirmUserEntityGrant;
getCurrentMenu: typeof getCurrentMenu;
getMenu: typeof getMenu;
createMenu: typeof createMenu;
createConditionalMenu: typeof createConditionalMenu;
deleteConditionalMenu: typeof deleteConditionalMenu;
batchGetArticle: typeof batchGetArticle;
getArticle: typeof getArticle;
createMaterial: typeof createMaterial;
batchGetMaterialList: typeof batchGetMaterialList;
getMaterial: typeof getMaterial;
};
export default aspectDict;

View File

@ -7,6 +7,7 @@ import { createWechatLogin } from './wechatLogin';
import { unbindingWechat } from './wechatUser';
import { getMpUnlimitWxaCode } from './wechatQrCode';
import { confirmUserEntityGrant } from './userEntityGrant';
import { getCurrentMenu, getMenu, createMenu, createConditionalMenu, deleteConditionalMenu, batchGetArticle, getArticle, createMaterial, batchGetMaterialList, getMaterial, } from './wechatMenu';
const aspectDict = {
mergeUser,
switchTo,
@ -31,5 +32,15 @@ const aspectDict = {
updateUserPassword,
getMpUnlimitWxaCode,
confirmUserEntityGrant,
getCurrentMenu,
getMenu,
createMenu,
createConditionalMenu,
deleteConditionalMenu,
batchGetArticle,
getArticle,
createMaterial,
batchGetMaterialList,
getMaterial,
};
export default aspectDict;

47
es/aspects/wechatMenu.d.ts vendored Normal file
View File

@ -0,0 +1,47 @@
import { EntityDict } from '../oak-app-domain';
import { BackendRuntimeContext } from '../context/BackendRuntimeContext';
export declare function getCurrentMenu<ED extends EntityDict, Cxt extends BackendRuntimeContext<ED>>(params: {
applicationId: string;
}, context: Cxt): Promise<any>;
export declare function getMenu<ED extends EntityDict, Cxt extends BackendRuntimeContext<ED>>(params: {
applicationId: string;
}, context: Cxt): Promise<any>;
export declare function createMenu<ED extends EntityDict, Cxt extends BackendRuntimeContext<ED>>(params: {
applicationId: string;
menuConfig: any;
}, context: Cxt): Promise<any>;
export declare function createConditionalMenu<ED extends EntityDict, Cxt extends BackendRuntimeContext<ED>>(params: {
applicationId: string;
menuConfig: any;
}, context: Cxt): Promise<any>;
export declare function deleteConditionalMenu<ED extends EntityDict, Cxt extends BackendRuntimeContext<ED>>(params: {
applicationId: string;
menuid: number;
}, context: Cxt): Promise<any>;
export declare function batchGetArticle<ED extends EntityDict, Cxt extends BackendRuntimeContext<ED>>(params: {
applicationId: string;
offset?: number;
count: number;
noContent?: 0 | 1;
}, context: Cxt): Promise<any>;
export declare function getArticle<ED extends EntityDict, Cxt extends BackendRuntimeContext<ED>>(params: {
applicationId: string;
article_id: string;
}, context: Cxt): Promise<any>;
export declare function createMaterial<ED extends EntityDict, Cxt extends BackendRuntimeContext<ED>>(params: {
applicationId: string;
type: 'image' | 'voice' | 'video' | 'thumb';
media: FormData;
description?: FormData;
}, context: Cxt): Promise<any>;
export declare function batchGetMaterialList<ED extends EntityDict, Cxt extends BackendRuntimeContext<ED>>(params: {
applicationId: string;
type: 'image' | 'video' | 'voice' | 'news';
offset?: number;
count: number;
}, context: Cxt): Promise<any>;
export declare function getMaterial<ED extends EntityDict, Cxt extends BackendRuntimeContext<ED>>(params: {
applicationId: string;
type: 'image' | 'video' | 'voice' | 'news';
media_id: string;
}, context: Cxt): Promise<any>;

147
es/aspects/wechatMenu.js Normal file
View File

@ -0,0 +1,147 @@
import { WechatSDK, } from 'oak-external-sdk';
async function getWechatPublicConfig(applicationId, context) {
const [application] = await context.select('application', {
data: {
id: 1,
config: 1,
type: 1,
},
filter: {
id: applicationId,
type: 'wechatPublic'
},
}, {
dontCollect: true
});
return application;
}
export async function getCurrentMenu(params, context) {
const application = await getWechatPublicConfig(params.applicationId, context);
if (application) {
const { type, config, systemId } = application;
let appId, appSecret;
const config2 = config;
appId = config2.appId;
appSecret = config2.appSecret;
const wechatInstance = WechatSDK.getInstance(appId, type, appSecret);
const result = await wechatInstance.getCurrentMenu();
return result;
}
}
export async function getMenu(params, context) {
const application = await getWechatPublicConfig(params.applicationId, context);
if (application) {
const { type, config, systemId } = application;
let appId, appSecret;
const config2 = config;
appId = config2.appId;
appSecret = config2.appSecret;
const wechatInstance = WechatSDK.getInstance(appId, type, appSecret);
const result = await wechatInstance.getMenu();
return result;
}
}
export async function createMenu(params, context) {
const application = await getWechatPublicConfig(params.applicationId, context);
if (application) {
const { type, config, systemId } = application;
let appId, appSecret;
const config2 = config;
appId = config2.appId;
appSecret = config2.appSecret;
const wechatInstance = WechatSDK.getInstance(appId, type, appSecret);
const result = await wechatInstance.createMenu(params.menuConfig);
return result;
}
}
export async function createConditionalMenu(params, context) {
const application = await getWechatPublicConfig(params.applicationId, context);
if (application) {
const { type, config, systemId } = application;
let appId, appSecret;
const config2 = config;
appId = config2.appId;
appSecret = config2.appSecret;
const wechatInstance = WechatSDK.getInstance(appId, type, appSecret);
const result = await wechatInstance.createConditionalMenu(params.menuConfig);
return result;
}
}
export async function deleteConditionalMenu(params, context) {
const application = await getWechatPublicConfig(params.applicationId, context);
if (application) {
const { type, config, systemId } = application;
let appId, appSecret;
const config2 = config;
appId = config2.appId;
appSecret = config2.appSecret;
const wechatInstance = WechatSDK.getInstance(appId, type, appSecret);
const result = await wechatInstance.deleteConditionalMenu(params.menuid);
return result;
}
}
export async function batchGetArticle(params, context) {
const application = await getWechatPublicConfig(params.applicationId, context);
if (application) {
const { type, config, systemId } = application;
let appId, appSecret;
const config2 = config;
appId = config2.appId;
appSecret = config2.appSecret;
const wechatInstance = WechatSDK.getInstance(appId, type, appSecret);
const result = await wechatInstance.batchGetArticle(params);
return result;
}
}
export async function getArticle(params, context) {
const application = await getWechatPublicConfig(params.applicationId, context);
if (application) {
const { type, config, systemId } = application;
let appId, appSecret;
const config2 = config;
appId = config2.appId;
appSecret = config2.appSecret;
const wechatInstance = WechatSDK.getInstance(appId, type, appSecret);
const result = await wechatInstance.getArticle(params);
return result;
}
}
export async function createMaterial(params, context) {
const application = await getWechatPublicConfig(params.applicationId, context);
if (application) {
const { type, config, systemId } = application;
let appId, appSecret;
const config2 = config;
appId = config2.appId;
appSecret = config2.appSecret;
const wechatInstance = WechatSDK.getInstance(appId, type, appSecret);
const result = await wechatInstance.createMaterial(params);
return result;
}
}
export async function batchGetMaterialList(params, context) {
const application = await getWechatPublicConfig(params.applicationId, context);
if (application) {
const { type, config, systemId } = application;
let appId, appSecret;
const config2 = config;
appId = config2.appId;
appSecret = config2.appSecret;
const wechatInstance = WechatSDK.getInstance(appId, type, appSecret);
const result = await wechatInstance.batchGetMaterialList(params);
return result;
}
}
export async function getMaterial(params, context) {
const application = await getWechatPublicConfig(params.applicationId, context);
if (application) {
const { type, config, systemId } = application;
let appId, appSecret;
const config2 = config;
appId = config2.appId;
appSecret = config2.appSecret;
const wechatInstance = WechatSDK.getInstance(appId, type, appSecret);
const result = await wechatInstance.getMaterial(params);
return result;
}
}

View File

@ -0,0 +1,7 @@
/// <reference types="react" />
declare const _default: (props: import("oak-frontend-base").ReactComponentProps<import("../../oak-app-domain").EntityDict, keyof import("../../oak-app-domain").EntityDict, false, {
type: "image" | "video" | "news" | "voice";
getMenuContent: (menuContent: any) => void;
applicationId: string;
}>) => import("react").ReactElement<any, string | import("react").JSXElementConstructor<any>>;
export default _default;

View File

@ -0,0 +1,109 @@
export default OakComponent({
isList: false,
properties: {
type: '',
getMenuContent: (menuContent) => undefined,
applicationId: '',
},
lifetimes: {
async ready() {
const { type, applicationId } = this.props;
let result;
if (type === 'news') {
result = await this.features.wechatMenu.batchGetArticle({ applicationId: applicationId, offset: 0, count: 10, noContent: 0 });
const modifiedResult = await Promise.all(result.item.map(async (ele) => {
const news_item = await Promise.all(ele.content.news_item.map(async (ele2) => {
const coverUrl = await this.getMaterialImg(ele2.thumb_media_id);
return {
...ele2,
coverUrl
};
}));
return {
...ele,
content: {
...ele.content,
news_item
}
};
}));
this.setState({
materials: modifiedResult,
total: result.total_count,
});
}
else {
result = await this.features.wechatMenu.batchGetMaterialList({ applicationId: applicationId, type: type, offset: 0, count: 10 });
this.setState({
materials: result.item,
total: result.total_count,
});
}
}
},
methods: {
async getMaterialList(page) {
const { applicationId } = this.props;
const { type } = this.props;
const offset = (page - 1) * 10;
const result = await this.features.wechatMenu.batchGetMaterialList({ applicationId: applicationId, type: type, offset, count: 10 });
this.setState({
materials: result.item,
total: result.total_count,
});
},
async getArticleList(page) {
const { applicationId } = this.props;
const offset = (page - 1) * 10;
const result = await this.features.wechatMenu.batchGetArticle({ applicationId: applicationId, offset, count: 10, noContent: 0 });
const modifiedResult = await Promise.all(result.item.map(async (ele) => {
const news_item = await Promise.all(ele.content.news_item.map(async (ele2) => {
const coverUrl = await this.getMaterialImg(ele2.thumb_media_id);
return {
...ele2,
coverUrl
};
}));
return {
...ele,
content: {
...ele.content,
news_item
}
};
}));
this.setState({
materials: modifiedResult,
total: result.total_count,
});
},
async upload(media, description) {
const { applicationId } = this.props;
const { type } = this.props;
console.log(media);
const result = await this.features.wechatMenu.createMaterial({ applicationId: applicationId, type: type, media, description });
if (result && result.media_id) {
this.setMessage({
type: 'success',
content: '上传成功',
});
this.getMaterialList(1);
return true;
}
else {
return false;
}
},
async getMaterialImg(media_id) {
const { applicationId } = this.props;
const imgFile = await this.features.wechatMenu.getMaterial({ applicationId: applicationId, type: 'image', media_id });
return new Promise((resolve) => {
const reader = new FileReader();
reader.readAsDataURL(imgFile);
reader.onload = function (e) {
resolve(e.target?.result);
};
});
}
}
});

View File

@ -0,0 +1,22 @@
.container {
display: flex;
flex-direction: column;
width: 100%;
.title {
font-size: 16px;
}
.upload {
display: flex;
flex-direction: row;
justify-content: flex-end;
align-items: center;
margin: 20px 0 0 0;
.help {
color: #B1B2B3;
margin-right: 10px;
}
}
.list {
margin-top: 20px;
}
}

View File

@ -0,0 +1,12 @@
import { EntityDict } from "../../oak-app-domain";
import { WebComponentProps } from 'oak-frontend-base';
export default function Render(props: WebComponentProps<EntityDict, keyof EntityDict, true, {
type: string;
materials: any[];
total: number;
getMenuContent: (menuContent: any) => void;
}, {
getMaterialList: (page: number) => void;
getArticleList: (page: number) => void;
upload: (media: FormData, description?: FormData) => boolean;
}>): import("react/jsx-runtime").JSX.Element;

View File

@ -0,0 +1,246 @@
import { Fragment as _Fragment, jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
import { useState, useEffect } from 'react';
import { Modal, Button, Table, Space, Upload, Form, Input, Popover } from 'antd';
const { TextArea } = Input;
import { DownloadOutlined } from '@ant-design/icons';
import Style from './web.module.less';
import dayjs from 'dayjs';
import ShowNews from '../wechatMenu/showNews';
export default function Render(props) {
const { type, materials, total, getMenuContent } = props.data;
const { getMaterialList, setMessage, upload, getArticleList } = props.methods;
const [currentPage, setCurrentPage] = useState(1);
const [upsertOpen, setUpsertOpen] = useState(false);
const [title, setTitle] = useState('');
const [introduction, setIntroduction] = useState('');
const [fileList, setFileList] = useState([]);
const [video, setVideo] = useState(new FormData);
const checkFileType = (filename) => {
const fileExtension = filename?.split('.')?.pop()?.toLowerCase();
let allowedExtensions = [];
if (type === 'image') {
allowedExtensions = ['bmp', 'png', 'jpeg', 'jpg', 'gif'];
}
else if (type === 'voice') {
allowedExtensions = ['mp3', 'wma', 'wav', 'amr'];
}
else {
allowedExtensions = ['mp4'];
}
if (allowedExtensions.includes(fileExtension)) {
return true;
}
else {
setMessage({
content: '文件类型错误',
type: 'error'
});
return false;
}
};
const uploadFile = async (file) => {
if (checkFileType(file.name)) {
const formData = new FormData();
formData.append('media', file);
console.log(file);
upload(formData);
}
else {
return;
}
};
const fileChange = (info) => {
setFileList(info.fileList);
};
const uploadVideo = async (file) => {
if (checkFileType(file.name)) {
const formData = new FormData();
formData.append('media', file);
setVideo(formData);
const updataFileList = fileList.map((ele) => {
return {
...ele,
status: 'done'
};
});
fileChange({ fileList: updataFileList });
}
else {
const updataFileList = fileList.map((ele) => {
return {
...ele,
status: 'error'
};
});
fileChange({ fileList: updataFileList });
}
};
useEffect(() => {
if (!open) {
setTitle('');
setIntroduction('');
setFileList([]);
}
}, [open]);
const columns = [
{
dataIndex: 'serial-number',
title: '序号',
render: (value, record, index) => {
return index + 1;
},
width: 100
},
{
dataIndex: 'name',
title: '名称',
},
{
dataIndex: 'update_time',
title: '更新时间',
render: (value, record, index) => {
return _jsx(_Fragment, { children: dayjs(value).format('YYYY-MM-DD HH:mm') });
}
},
];
const newsColumns = [
{
dataIndex: 'serial-number',
title: '序号',
render: (value, record, index) => {
return index + 1;
},
width: 100
},
{
dataIndex: 'coverImg',
title: '封面图',
render: (value, record, index) => {
return (_jsx("div", { children: record.content.news_item.map((ele) => (_jsx("div", { children: _jsx("img", { style: { width: 100 }, src: ele.coverUrl }) }))) }));
}
},
{
dataIndex: 'title',
title: '图文消息标题',
render: (value, record, index) => {
return (_jsx("div", { children: record.content.news_item.map((ele) => (_jsx("div", { children: ele.title }))) }));
}
},
{
// dataIndex: 'author',
title: '作者',
render: (value, record, index) => {
return (_jsx("div", { children: record.content.news_item.map((ele) => (_jsx("div", { children: ele.author }))) }));
}
},
{
dataIndex: 'digest',
title: '图文信息摘要',
render: (value, record, index) => {
return (_jsx("div", { children: record.content.news_item.map((ele) => (_jsx("div", { children: ele.digest }))) }));
}
},
{
dataIndex: 'update_time',
title: '更新时间',
render: (value, record, index) => {
return _jsx(_Fragment, { children: dayjs(value).format('YYYY-MM-DD HH:mm') });
}
},
{
dataIndex: 'op',
title: '操作',
render: (value, record, index) => {
return _jsx(Popover, { content: _jsx("div", { style: { padding: 12 }, children: _jsx(ShowNews, { oakAutoUnmount: true, news: record.content.news_item }) }), children: _jsx("div", { style: { cursor: 'pointer', color: '#1677ff' }, children: "\u9884\u89C8" }) });
}
}
];
if (type === 'image') {
columns.splice(1, 0, {
dataIndex: 'url',
title: '图片',
render: (value, record, index) => {
return _jsx("img", { style: { width: 120, height: 70 }, src: value });
},
});
}
else if (type === 'voice') {
columns.splice(1, 0, {
dataIndex: 'url',
title: '音频',
render: (value, record, index) => {
return _jsxs("a", { href: value, download: true, style: { color: '#1677FF', cursor: 'pointer' }, children: [_jsx(DownloadOutlined, {}), record.media_id] });
},
});
}
else if (type === 'video') {
columns.splice(1, 0, {
dataIndex: 'url',
title: '视频',
render: (value, record, index) => {
return _jsxs("a", { href: value, download: true, style: { color: '#1677FF', cursor: 'pointer' }, children: [_jsx(DownloadOutlined, {}), record.media_id] });
},
});
}
else {
}
return (_jsxs("div", { className: Style.container, children: [_jsx("div", { className: Style.title, children: type === 'news' ? '选择图文' : type === 'image' ? '选择图片' : type === 'voice' ? '插入音频' : '选择视频' }), type !== 'news' && _jsxs("div", { className: Style.upload, children: [_jsx("div", { className: Style.help, children: type === 'image' ? '大小不超过10M' : type === 'voice' ? '由于版本兼容的原因,你暂时只可以选择60秒内的音频发送' : null }), type === 'video' ? (_jsx(Button, { onClick: () => {
setUpsertOpen(true);
}, children: "\u4E0A\u4F20\u89C6\u9891" })) : (_jsx(Upload, { maxCount: 1, showUploadList: false, customRequest: ({ file }) => {
uploadFile(file);
}, children: _jsxs(Button, { children: ["\u4E0A\u4F20", type === 'image' ? '图片' : '音频'] }) })), _jsx(Modal, { open: upsertOpen, onCancel: () => setUpsertOpen(false), title: '上传视频', footer: _jsxs(Space, { children: [_jsx(Button, { type: 'primary', onClick: () => {
if (title.length === 0) {
setMessage({
type: 'warning',
content: '标题不能为空'
});
return;
}
if (introduction.length === 0) {
setMessage({
type: 'warning',
content: '视频介绍不能为空'
});
return;
}
if (fileList.length === 0 || fileList[0].status === 'error') {
setMessage({
type: 'warning',
content: '请上传视频文件'
});
return;
}
const formData = new FormData;
const descriptionData = {
title,
introduction,
};
formData.append('description', JSON.stringify(descriptionData));
if (upload(video, formData)) {
setUpsertOpen(false);
}
}, children: "\u4E0A\u4F20" }), _jsx(Button, { onClick: () => setUpsertOpen(false), children: "\u53D6\u6D88" })] }), children: _jsxs("div", { children: [_jsx(Form.Item, { label: _jsx("div", { className: Style.label, children: "\u6807\u9898" }), required: true, labelAlign: 'right', labelCol: { span: 4 }, children: _jsx(Input, { showCount: true, maxLength: 20, value: title, onChange: (val) => setTitle(val.target.value) }) }), _jsx(Form.Item, { label: _jsx("div", { className: Style.label, children: "\u89C6\u9891\u4ECB\u7ECD" }), required: true, children: _jsx(TextArea, { showCount: true, maxLength: 300, value: introduction, autoSize: { minRows: 5 }, onChange: (val) => setIntroduction(val.target.value) }) }), _jsx(Form.Item, { label: _jsx("div", { className: Style.label, children: "\u4E0A\u4F20\u89C6\u9891" }), required: true, children: _jsx(Upload, { customRequest: ({ file }) => uploadVideo(file), maxCount: 1, onChange: fileChange, fileList: fileList, children: _jsxs(Button, { children: [_jsx(DownloadOutlined, {}), fileList.length > 0 ? '重新' : '', "\u4E0A\u4F20"] }) }) })] }) })] }), _jsx("div", { className: Style.list, children: _jsx(Table, { rowKey: type === 'news' ? 'article_id' : 'media_id', dataSource: materials, columns: type === 'news' ? newsColumns : columns, pagination: {
total: total,
pageSize: 10,
current: currentPage,
onChange: (page, pageSize) => {
setCurrentPage(page);
if (type === 'news') {
getArticleList(page);
}
else {
getMaterialList(page);
}
},
}, rowSelection: {
type: 'radio',
onSelect: (record) => {
if (type === 'news') {
getMenuContent(record);
}
else {
getMenuContent(record);
}
},
} }) })] }));
}

View File

@ -0,0 +1,15 @@
/// <reference types="react" />
declare const _default: (props: import("oak-frontend-base").ReactComponentProps<import("../../../oak-app-domain").EntityDict, keyof import("../../../oak-app-domain").EntityDict, false, {
id: string;
config: any;
menuIndex: number;
changeConfig: (config: any) => void;
menuType: string;
getSelectedBtn: (selectedBtn: number) => void;
getSelectedSubBtn: (selectedSubBtn: number) => void;
getCurrentIndex: (currentIndex: number) => void;
errorIndex: number[];
isPreview: boolean;
open: boolean;
}>) => import("react").ReactElement<any, string | import("react").JSXElementConstructor<any>>;
export default _default;

View File

@ -0,0 +1,81 @@
export default OakComponent({
isList: false,
properties: {
id: '',
config: null,
menuIndex: 0,
changeConfig: (config) => undefined,
menuType: '',
getSelectedBtn: (selectedBtn) => undefined,
getSelectedSubBtn: (selectedSubBtn) => undefined,
getCurrentIndex: (currentIndex) => undefined,
errorIndex: [],
isPreview: false,
open: false,
},
data: {},
methods: {
deleteMenuItem(index) {
const { config, changeConfig, menuIndex, menuType } = this.props;
config.button.splice(index, 1);
changeConfig(config);
this.setMessage({
content: '操作成功',
type: 'success'
});
},
toRight(index) {
const { config, changeConfig, menuIndex, menuType } = this.props;
config.button = [
...config.button.slice(0, index - 1),
config.button[index],
config.button[index - 1],
...config.button.slice(index + 1)
];
changeConfig(config);
},
toLeft(index) {
const { config, changeConfig, menuIndex, menuType } = this.props;
config.button = [
...config.button.slice(0, index - 2),
config.button[index - 1],
config.button[index - 2],
...config.button.slice(index)
];
changeConfig(config);
},
toUp(currentIndex, index) {
const { config, changeConfig, menuIndex, menuType } = this.props;
let menu = config.button[currentIndex];
const subMenu = [
...menu.sub_button.slice(0, index - 2),
menu.sub_button[index - 1],
menu.sub_button[index - 2],
...menu.sub_button.slice(index)
];
config.button[currentIndex].sub_button = subMenu;
changeConfig(config);
},
toDown(currentIndex, index) {
const { config, changeConfig, menuIndex, menuType } = this.props;
let menu = config.button[currentIndex];
const subMenu = [
...menu.sub_button.slice(0, index - 1),
menu.sub_button[index],
menu.sub_button[index - 1],
...menu.sub_button.slice(index + 1)
];
config.button[currentIndex].sub_button = subMenu;
changeConfig(config);
},
deleteSubMenuItem(index, currentIndex) {
const { config, changeConfig, menuIndex, menuType } = this.props;
config.button[currentIndex].sub_button.splice(index, 1);
changeConfig(config);
this.setMessage({
content: '操作成功',
type: 'success'
});
},
}
});

View File

@ -0,0 +1,180 @@
.container {
width: 100%;
.phone {
display: flex;
flex-direction: column;
width: 100%;
background: #fcfcfc;
border-radius: 8px;
.topBar {
display: flex;
flex-direction: row;
justify-content: space-between;
height: 30px;
margin: 8px 16px 10px 16px;
align-items: center;
.time {
font-size: 12px;
font-weight: bold;
}
.icons {
display: flex;
flex-direction: row;
}
}
.actionBar {
display: flex;
flex-direction: row;
justify-content: space-between;
margin: 0 10px;
}
.page {
height: 412px;
}
.bottomBar {
height: 68px;
display: flex;
flex-direction: row;
background: #fcfcfc;
border-bottom-left-radius: 8px;
border-bottom-right-radius: 8px;
border-top: 1px solid #EDEEEF;
.keyBoard {
width: 60px;
}
.menu {
flex: 1;
display: flex;
flex-direction: row;
cursor: pointer;
.buttonGroup {
top: 73px;
position: absolute;
justify-content: center;
align-items: center;
display: flex;
height: 48px;
min-width: 48px;
border-radius: 24px;
background: #fcfcfc;
font-size: 24px;
padding: 5px;
box-shadow: 0 1px 6px #e4e8eb;
.buttonItem {
height: 38px;
width: 38px;
border-radius: 50%;
justify-content: center;
align-items: center;
display: flex;
}
.buttonItem:hover {
background: #EDEEEF;
}
}
.menuItem {
flex: 1;
display: flex;
flex-direction: column;
justify-content: center;
align-items: center;
height: 68px;
width: 80px;
position: relative;
.menuName {
width: 100%;
height: 33px;
border-left: 1px solid #EDEEEF;
display: flex;
justify-content: center;
align-items: center;
}
}
.button2 {
margin: 17px 0;
flex: 1;
display: flex;
justify-content: center;
align-items: center;
border-left: 1px solid #EDEEEF;
color: #4C4D4E;
}
}
.button {
flex: 1;
display: flex;
justify-content: center;
align-items: center;
border: 1px dashed #1677FF;
font-size: 14px;
color: #1677FF;
cursor: pointer;
}
}
}
}
:global {
.ant-popover-inner {
padding: 0 !important;
}
}
.subMenuContent {
display: flex;
flex-direction: row;
align-items: center;
.subButtonGroup {
display: flex;
flex-direction: column;
justify-content: center;
align-items: center;
width: 48px;
min-height: 48px;
border-radius: 24px;
background: #fcfcfc;
font-size: 24px;
padding: 5px;
position: absolute;
left: 90px;
box-shadow: 0 1px 6px #e4e8eb;
.buttonItem {
height: 38px;
width: 38px;
border-radius: 50%;
justify-content: center;
align-items: center;
display: flex;
cursor: pointer;
}
.buttonItem:hover {
background: #EDEEEF;
}
}
}
.subMenuItem {
width: 86px;
height: 49px;
text-align: center;
padding: 12px 2px;
cursor: pointer;
white-space: nowrap;
overflow: hidden;
text-overflow: ellipsis;
border-bottom: 1px solid #EDEEEF;
}

View File

@ -0,0 +1,25 @@
import { WechatPublicInstance } from 'oak-external-sdk';
import { EntityDict } from "../../../oak-app-domain";
import { WebComponentProps } from 'oak-frontend-base';
export default function Render(props: WebComponentProps<EntityDict, keyof EntityDict, false, {
config: any;
menuIndex: number;
file: File;
wechatInstance: WechatPublicInstance;
errorIndex: number[];
menuType: string;
changeConfig: (config: any) => void;
getSelectedBtn: (selectedBtn: number) => void;
getSelectedSubBtn: (selectedSubBtn: number) => void;
getCurrentIndex: (currentIndex: number) => void;
isPreview: boolean;
open: boolean;
}, {
setConfig: (index: number, content: any, currentIndex?: number) => void;
deleteMenuItem: (index: number) => void;
deleteSubMenuItem: (index: number, currentIndex: number) => void;
toRight: (index: number) => void;
toLeft: (index: number) => void;
toUp: (currentIndex: number, index: number) => void;
toDown: (currentIndex: number, index: number) => void;
}>): import("react/jsx-runtime").JSX.Element;

View File

@ -0,0 +1,185 @@
import { jsx as _jsx, jsxs as _jsxs, Fragment as _Fragment } from "react/jsx-runtime";
import { useState, useEffect } from 'react';
import { Modal, Popover } from 'antd';
const { confirm } = Modal;
import Style from './web.module.less';
import { WifiOutlined, LeftOutlined, ArrowLeftOutlined, ArrowRightOutlined, UserOutlined, ArrowDownOutlined, DeleteOutlined, ArrowUpOutlined, PlusOutlined } from '@ant-design/icons';
export default function Render(props) {
const { config, errorIndex, menuIndex, menuType, changeConfig, getSelectedBtn, getSelectedSubBtn, getCurrentIndex, isPreview, open, } = props.data;
const { deleteMenuItem, toRight, toLeft, toUp, toDown, deleteSubMenuItem, } = props.methods;
const [selectedBtn, setSelectedBtn] = useState(0);
const [selectedSubBtn, setSelectedSubBtn] = useState(0);
const [currentIndex, setCurrentIndex] = useState(1);
const [onlyOne, setOnlyOne] = useState(true);
const [currentMenuType, setCurrentMenuType] = useState(0);
useEffect(() => {
if (config && config.button && config.button[0] && onlyOne) {
setSelectedBtn(1);
getSelectedBtn(1);
setOnlyOne(false);
}
}, [config]);
useEffect(() => {
if (selectedBtn !== 0) {
setSelectedSubBtn(0);
getSelectedSubBtn(0);
setCurrentIndex(selectedBtn - 1);
getCurrentIndex(selectedBtn - 1);
}
}, [selectedBtn]);
useEffect(() => {
if (selectedSubBtn !== 0) {
setSelectedBtn(0);
getSelectedBtn(0);
}
}, [selectedSubBtn]);
useEffect(() => {
if (menuType && menuType === 'common') {
setCurrentMenuType(1);
return;
}
if (menuType && menuType === 'conditional') {
setCurrentMenuType(2);
return;
}
}, [menuType]);
return (_jsx("div", { className: Style.container, children: _jsxs("div", { className: Style.phone, children: [_jsxs("div", { className: Style.topBar, children: [_jsx("div", { className: Style.time, children: "1:21" }), _jsx("div", { className: Style.icons, children: _jsx(WifiOutlined, { style: { fontSize: 12 } }) })] }), _jsxs("div", { className: Style.actionBar, children: [_jsx(LeftOutlined, { style: { fontSize: 18 } }), _jsx(UserOutlined, { style: { fontSize: 18 } })] }), _jsx("div", { className: Style.page }), _jsxs("div", { className: Style.bottomBar, children: [_jsx("div", { className: Style.keyBoard }), config && config.button && config.button.length > 0 ? (_jsxs("div", { className: Style.menu, children: [config.button.map((ele, index) => (_jsx(Popover, { open: !open && !isPreview && currentIndex === index && ((menuType === 'common' && currentMenuType === 1) || (menuType === 'conditional' && currentMenuType === 2)), trigger: 'click', content: _jsx("div", { className: Style.subMenu, children: config.button[index].sub_button.length > 0 ? (_jsxs(_Fragment, { children: [config.button[index].sub_button.map((ele, index2) => (_jsxs("div", { className: Style.subMenuContent, children: [_jsx("div", { className: Style.subMenuItem, style: errorIndex?.includes((index + 1) * 10 + index2) ? {
border: '1px solid #FF4D4F',
color: '#FF4D4F'
}
:
selectedSubBtn === index2 + 1 ?
{
border: '1px solid #1677FF',
color: '#1677FF'
} :
{}, onClick: () => {
setSelectedSubBtn(index2 + 1);
getSelectedSubBtn(index2 + 1);
}, children: ele.name }), selectedSubBtn === index2 + 1 &&
_jsxs("div", { className: Style.subButtonGroup, children: [selectedSubBtn > 1
&& config.button[currentIndex].sub_button.length !== 1 &&
_jsx("div", { className: Style.buttonItem, onClick: () => {
toUp(currentIndex, selectedSubBtn);
setSelectedSubBtn(selectedSubBtn - 1);
getSelectedSubBtn(selectedSubBtn - 1);
}, children: _jsx(ArrowUpOutlined, {}) }), _jsx("div", { className: Style.buttonItem, onClick: () => {
const modal = confirm({
title: '确定删除该菜单吗?',
content: '删除后不可恢复',
okText: '确定',
cancelText: '取消',
onOk: async (e) => {
if (selectedSubBtn !== 1 && config.button[currentIndex].sub_button.length > 1) {
setSelectedSubBtn(selectedSubBtn - 1);
getSelectedSubBtn(selectedSubBtn - 1);
}
else if (selectedSubBtn === 1 && config.button[currentIndex].sub_button.length > 1) {
setSelectedSubBtn(1);
getSelectedSubBtn(1);
}
else {
setSelectedBtn(currentIndex + 1);
getSelectedBtn(currentIndex + 1);
}
deleteSubMenuItem(selectedSubBtn - 1, currentIndex);
modal.destroy();
},
});
}, children: _jsx(DeleteOutlined, {}) }), selectedSubBtn < config.button[currentIndex].sub_button.length
&& config.button[currentIndex].sub_button.length > 1 &&
_jsx("div", { className: Style.buttonItem, onClick: () => {
toDown(currentIndex, selectedSubBtn);
setSelectedSubBtn(selectedSubBtn + 1);
getSelectedSubBtn(selectedSubBtn + 1);
}, children: _jsx(ArrowDownOutlined, {}) })] })] }))), config.button[index].sub_button.length !== 5 &&
_jsxs("div", { style: { border: 0 }, className: Style.subMenuItem, onClick: () => {
config.button[index] = {
name: config.button[index].name,
sub_button: [
...config.button[index].sub_button,
{
name: '子菜单名称',
}
]
};
changeConfig(config);
setSelectedSubBtn(config.button[index].sub_button.length);
getSelectedSubBtn(config.button[index].sub_button.length);
}, children: [_jsx(PlusOutlined, {}), "\u6DFB\u52A0"] })] })) : (_jsxs("div", { style: { border: 0 }, className: Style.subMenuItem, onClick: () => {
config.button[index] = {
name: config.button[index].name,
sub_button: [
{
name: '子菜单名称',
}
]
};
changeConfig(config);
setSelectedSubBtn(1);
getSelectedSubBtn(1);
}, children: [_jsx(PlusOutlined, {}), "\u6DFB\u52A0"] })) }), children: _jsxs("div", { className: Style.menuItem, onClick: () => { setSelectedBtn(index + 1); getSelectedBtn(index + 1); }, style: errorIndex?.includes(index) ?
{ margin: 0, border: '1px solid #FF4D4F' }
:
selectedBtn === index + 1 ?
{ margin: 0, border: '1px solid #1677FF', color: '#1677FF' }
:
{}, children: [_jsx("div", { className: Style.menuName, style: errorIndex?.includes(index) ? {
color: '#FF4D4F'
} : {}, children: ele.name }), selectedBtn === index + 1 &&
_jsxs("div", { className: Style.buttonGroup, children: [selectedBtn > 1
&& config.button.length !== 1
&& _jsx("div", { className: Style.buttonItem, onClick: () => {
toLeft(selectedBtn);
setSelectedBtn(selectedBtn - 1);
getSelectedBtn(selectedBtn - 1);
}, style: { color: '#1F1F1F' }, children: _jsx(ArrowLeftOutlined, {}) }), _jsx("div", { className: Style.buttonItem, onClick: () => {
const modal = confirm({
title: '确定删除该菜单吗?',
content: '删除后不可恢复',
okText: '确定',
cancelText: '取消',
onOk: async (e) => {
if (selectedBtn !== 1 && config.button.length > 1) {
setSelectedBtn(selectedBtn - 1);
getSelectedBtn(selectedBtn - 1);
}
else if (selectedBtn === 1 && config.button.length > 1) {
setSelectedBtn(1);
getSelectedBtn(1);
}
else {
setSelectedBtn(currentIndex + 1);
getSelectedBtn(currentIndex + 1);
}
deleteMenuItem(selectedBtn - 1);
modal.destroy();
},
});
}, style: { color: '#1F1F1F' }, children: _jsx(DeleteOutlined, {}) }), selectedBtn < config.button.length
&& config.button.length > 1 &&
_jsx("div", { className: Style.buttonItem, onClick: () => {
toRight(selectedBtn);
setSelectedBtn(selectedBtn + 1);
getSelectedBtn(selectedBtn + 1);
}, style: { color: '#1F1F1F' }, children: _jsx(ArrowRightOutlined, {}) })] })] }) }))), config.button.length !== 3 &&
_jsx("div", { className: Style.button2, onClick: () => {
config.button = [
...config.button, {
name: '菜单名称',
sub_button: [],
}
];
changeConfig(config);
setSelectedBtn(config.button.length);
getSelectedBtn(config.button.length);
}, children: _jsx(PlusOutlined, {}) })] })) : (_jsxs("div", { className: Style.button, onClick: () => {
config.button = [{
name: '菜单名称',
sub_button: [],
}];
changeConfig(config);
setSelectedBtn(1);
getSelectedBtn(1);
}, children: [_jsx(PlusOutlined, {}), "\u6DFB\u52A0\u83DC\u5355"] }))] })] }) }));
}

View File

@ -0,0 +1,7 @@
/// <reference types="react" />
declare const _default: (props: import("oak-frontend-base").ReactComponentProps<import("../../../oak-app-domain").EntityDict, "wechatMenu", true, {
applicationId: string;
tagId: string;
menuType: string;
}>) => import("react").ReactElement<any, string | import("react").JSXElementConstructor<any>>;
export default _default;

View File

@ -0,0 +1,66 @@
export default OakComponent({
isList: true,
entity: 'wechatMenu',
projection: {
id: 1,
menuConfig: 1,
applicationId: 1,
application: {
id: 1,
type: 1,
config: 1,
},
publishState: 1,
wechatPublicTagId: 1,
menuId: 1,
},
formData({ data: rows }) {
return {
id: rows?.[0]?.id,
config: rows?.[0]?.menuConfig,
menuId: rows?.[0]?.menuId,
};
},
properties: {
applicationId: '',
tagId: '',
menuType: '',
},
lifetimes: {
async ready() {
const { applicationId, tagId } = this.props;
const [conditionalmenu] = this.features.cache.get('wechatMenu', {
data: {
id: 1,
menuConfig: 1,
menuId: 1,
wechatPublicTagId: 1,
applicationId: 1,
publishState: 1,
},
filter: {
applicationId,
wechatPublicTagId: tagId
}
});
if (!conditionalmenu) {
this.addItem({
wechatPublicTagId: tagId,
menuConfig: { button: [], matchrule: { tag_id: tagId } }
});
}
}
},
filters: [
{
filter() {
const { applicationId, tagId } = this.props;
return {
applicationId,
wechatPublicTagId: tagId
};
}
},
],
methods: {},
});

View File

@ -0,0 +1,450 @@
.container {
width: 100%;
display: flex;
flex-direction: row;
.tagList {
width: 20%;
margin-right: 20px;
}
.tagHelp {
background: var(--oak-bg-color-container);
padding: 10px;
width: 100%;
border-top-left-radius: 8px;
border-top-right-radius: 8px;
}
.content {
display: flex;
flex-direction: row;
width: 100%;
.leftBar {
width: 300px;
margin-right: 25px;
.phone {
display: flex;
flex-direction: column;
width: 100%;
background: #fcfcfc;
border-radius: 8px;
.topBar {
display: flex;
flex-direction: row;
justify-content: space-between;
height: 30px;
margin: 8px 16px 10px 16px;
align-items: center;
.time {
font-size: 12px;
font-weight: bold;
}
.icons {
display: flex;
flex-direction: row;
}
}
.actionBar {
display: flex;
flex-direction: row;
justify-content: space-between;
margin: 0 10px;
}
.page {
height: 412px;
}
.bottomBar {
height: 68px;
display: flex;
flex-direction: row;
background: #fcfcfc;
border-bottom-left-radius: 8px;
border-bottom-right-radius: 8px;
border-top: 1px solid #EDEEEF;
.keyBoard {
width: 60px;
}
.menu {
flex: 1;
display: flex;
flex-direction: row;
cursor: pointer;
position: relative;
.buttonGroup {
position: absolute;
top: 73px;
justify-content: center;
align-items: center;
display: flex;
height: 48px;
min-width: 48px;
border-radius: 24px;
background: #fcfcfc;
font-size: 24px;
padding: 5px;
box-shadow: 0 1px 6px #e4e8eb;
.buttonItem {
height: 38px;
width: 38px;
border-radius: 50%;
justify-content: center;
align-items: center;
display: flex;
}
.buttonItem:hover {
background: #EDEEEF;
}
}
.menuItem {
flex: 1;
display: flex;
justify-content: center;
align-items: center;
.menuName {
width: 100%;
height: 33px;
border-left: 1px solid #EDEEEF;
display: flex;
justify-content: center;
align-items: center;
}
}
.button2 {
margin: 17px 0;
flex: 1;
display: flex;
justify-content: center;
align-items: center;
border-left: 1px solid #EDEEEF;
color: #4C4D4E;
}
}
.button {
flex: 1;
display: flex;
justify-content: center;
align-items: center;
border: 1px dashed #1677FF;
font-size: 14px;
color: #1677FF;
cursor: pointer;
}
}
}
}
.rightBar {
flex: 1;
.editor {
display: flex;
flex-direction: row;
border: 1px solid #dbdbdb;
width: 600px;
position: relative;
}
.content {
padding: 40px;
border-bottom: 1px solid #EDEEEF;
background: #fcfcfc;
border-top-left-radius: 8px;
border-top-right-radius: 8px;
display: flex;
flex-direction: column;
.title {
font-size: 16px;
font-weight: bold;
margin-bottom: 32px;
}
.label {
width: 94px;
text-align: left;
}
.coverImage {
width: 300px;
display: flex;
flex-direction: row;
.img {
width: 100%;
object-fit: contain;
}
}
.fileCover {
width: 300px;
display: flex;
flex-direction: row;
align-items: center;
}
.buttonGroup {
margin-left: 10px;
display: flex;
flex-direction: column;
justify-content: center;
align-items: center;
width: 36px;
min-height: 36px;
border-radius: 18px;
background: #fcfcfc;
font-size: 18px;
padding: 3px;
box-shadow: 0 1px 6px #e4e8eb;
.buttonItem {
height: 30px;
width: 30px;
border-radius: 50%;
justify-content: center;
align-items: center;
display: flex;
cursor: pointer;
}
.buttonItem:hover {
background: #EDEEEF;
}
}
.menuContent {
display: flex;
flex-direction: row;
.item {
display: flex;
justify-content: center;
align-items: center;
padding: 10px;
background: #F6F7F8;
cursor: pointer;
}
.item:hover {
color: #1677FF;
}
}
.delete {
font-size: 14px;
color: #FF5557;
cursor: pointer;
width: 60px;
}
.delete:hover {
opacity: 0.7;
}
}
.actionBar {
display: flex;
justify-content: flex-end;
width: 100%;
background: #fcfcfc;
border-bottom-left-radius: 8px;
border-bottom-right-radius: 8px;
padding: 20px 40px 20px 40px;
}
.news {
width: 310px;
display: flex;
flex-direction: row;
border: 1px solid #dbdbdb;
border-radius: 4px;
.multiNews {
width: 100%;
display: flex;
flex-direction: column;
.cover {
width: 308px;
height: 130px;
border-top-left-radius: 8px;
border-top-right-radius: 8px;
.img {
object-fit: contain;
width: 100%;
height: 100%;
}
.articleTitle {
// color: #fff;
padding: 0 12px;
font-weight: bold;
font-size: 14px;
position: absolute;
top: 100px;
}
}
.newsItem {
display: flex;
flex-direction: row;
justify-content: space-between;
padding: 12px;
align-items: center;
.articleTitle {
width: 220px;
font-size: 14px;
color: #353535;
line-height: 48px;
border-bottom: 1px solid #dbdbdb;
font-weight: 500;
}
.imgCover {
object-fit: cover;
width: 48px;
height: 48px;
.img {
width: 100%;
height: 100%;
}
}
}
.newsItem:last-child {
.articleTitle {
border-bottom: 0;
}
}
}
.singleNews {
width: 100%;
display: flex;
flex-direction: column;
.cover {
width: 308px;
height: 130px;
border-top-left-radius: 4px;
border-top-right-radius: 4px;
.img {
object-fit: contain;
width: 100%;
height: 100%;
}
}
.articleTitle {
padding: 12px;
font-weight: bold;
font-size: 14px;
color: #353535;
font-weight: 500;
}
}
}
}
}
}
.phone {
display: flex;
flex-direction: column;
width: 374px;
background: #f0f0f0;
border-radius: 8px;
.topBar {
display: flex;
flex-direction: row;
justify-content: space-between;
height: 30px;
margin: 8px 16px 12px 16px;
align-items: center;
.time {
font-size: 14px;
font-weight: bold;
}
.icons {
display: flex;
flex-direction: row;
}
}
.actionBar {
display: flex;
flex-direction: row;
justify-content: space-between;
margin: 0 10px;
}
.page {
height: 450px;
}
.bottomBar {
height: 68px;
display: flex;
flex-direction: column;
background: #fcfcfc;
.keyBoard {
width: 60px;
}
}
}
:global {
.ant-popover-inner {
padding: 0 !important;
}
}
.subMenuContent {
display: flex;
flex-direction: row;
align-items: center;
.subButtonGroup {
display: flex;
flex-direction: column;
justify-content: center;
align-items: center;
width: 48px;
min-height: 48px;
border-radius: 24px;
background: #fcfcfc;
font-size: 24px;
padding: 5px;
position: absolute;
left: 90px;
box-shadow: 0 1px 6px #e4e8eb;
.buttonItem {
height: 38px;
width: 38px;
border-radius: 50%;
justify-content: center;
align-items: center;
display: flex;
cursor: pointer;
}
.buttonItem:hover {
background: #EDEEEF;
}
}
}
.subMenuItem {
width: 86px;
height: 49px;
text-align: center;
padding: 12px 2px;
cursor: pointer;
white-space: nowrap;
overflow: hidden;
text-overflow: ellipsis;
border-bottom: 1px solid #EDEEEF;
}

View File

@ -0,0 +1,13 @@
import { WebComponentProps } from 'oak-frontend-base';
import { EntityDict } from "../../../oak-app-domain";
export default function Render(props: WebComponentProps<EntityDict, 'wechatMenu', true, {
id: string;
config: any;
file: File;
errorIndex: number[];
oakId: string;
menuIndex: number;
applicationId: string;
menuType: string;
menuId: number;
}, {}>): import("react/jsx-runtime").JSX.Element | null;

View File

@ -0,0 +1,61 @@
import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
import { useState } from 'react';
import Style from './web.module.less';
import { Modal } from 'antd';
import Preview from '../preview';
import ActionPhone from '../actionPhone';
import MenuInfo from '../menuInfo';
export default function Render(props) {
const { data, methods } = props;
const { id, oakFullpath, config, menuIndex, applicationId, menuType, menuId, } = data;
const { updateItem, removeItem, execute, } = methods;
const [isPreview, setIsPreview] = useState(false);
const [selectedBtn, setSelectedBtn] = useState(0);
const [selectedSubBtn, setSelectedSubBtn] = useState(0);
const [currentIndex, setCurrentIndex] = useState(1);
const [open, setOpen] = useState(false);
const [errorIndex, setErrorIndex] = useState([]);
const changeConfig = (config) => {
updateItem({
menuConfig: config
}, id);
};
const changePublishState = (publishState) => {
updateItem({
publishState,
}, id);
};
const changeMenuId = (menuId) => {
updateItem({
menuId
}, id);
};
const deleteMenu = () => {
removeItem(id);
};
const getSelectedBtn = (selectedBtn) => {
setSelectedBtn(selectedBtn);
};
const getSelectedSubBtn = (selectedSubBtn) => {
setSelectedSubBtn(selectedSubBtn);
};
const getCurrentIndex = (currentIndex) => {
setCurrentIndex(currentIndex);
};
const getErrorIndex = (errorIndex) => {
setErrorIndex(errorIndex);
};
const createMenu = async () => {
await execute();
};
const changeIsPreview = (isPreview) => {
setIsPreview(isPreview);
};
const getOpen = (open) => {
setOpen(open);
};
if (oakFullpath) {
return (_jsx("div", { className: Style.container, children: _jsxs("div", { className: Style.content, children: [_jsx("div", { className: Style.leftBar, children: _jsx(ActionPhone, { oakAutoUnmount: true, config: config, menuIndex: menuIndex, changeConfig: changeConfig, menuType: menuType, getSelectedBtn: getSelectedBtn, getSelectedSubBtn: getSelectedSubBtn, getCurrentIndex: getCurrentIndex, errorIndex: errorIndex, isPreview: isPreview, open: open }) }), _jsx("div", { className: Style.rightBar, children: _jsx(MenuInfo, { oakAutoUnmount: true, config: config, menuIndex: menuIndex, changeConfig: changeConfig, changePublishState: changePublishState, selectedBtn: selectedBtn, selectedSubBtn: selectedSubBtn, currentIndex: currentIndex, getErrorIndex: getErrorIndex, createMenu: createMenu, changeIsPreview: changeIsPreview, getOpen: getOpen, menuType: menuType, applicationId: applicationId, changeMenuId: changeMenuId, deleteMenu: deleteMenu, menuId: menuId }) }), _jsx(Modal, { title: '\u83DC\u5355\u9884\u89C8', open: isPreview, onCancel: () => setIsPreview(false), footer: null, width: 424, children: _jsx(Preview, { button: config?.button, applicationId: applicationId }) })] }) }));
}
return null;
}

5
es/components/wechatMenu/index.d.ts vendored Normal file
View File

@ -0,0 +1,5 @@
/// <reference types="react" />
declare const _default: (props: import("oak-frontend-base").ReactComponentProps<import("../../oak-app-domain").EntityDict, keyof import("../../oak-app-domain").EntityDict, true, {
applicationId: string;
}>) => import("react").ReactElement<any, string | import("react").JSXElementConstructor<any>>;
export default _default;

View File

@ -0,0 +1,38 @@
export default OakComponent({
isList: true,
properties: {
applicationId: '',
},
lifetimes: {
async ready() {
const { applicationId } = this.props;
const result = await this.features.wechatMenu.getCurrentMenu({ applicationId: applicationId });
if (result.is_menu_open === 1) {
const { data: wechatMenu } = await this.features.cache.refresh('wechatMenu', {
data: {
id: 1,
applicationId: 1,
},
filter: {
applicationId,
}
});
if (wechatMenu && wechatMenu[0]) {
this.setState({
menuId: wechatMenu[0].id,
});
}
this.setState({
is_menu_open: true,
applicationId,
});
}
else {
this.setState({
is_menu_open: false,
});
}
}
},
methods: {},
});

View File

@ -0,0 +1,7 @@
/// <reference types="react" />
declare const _default: (props: import("oak-frontend-base").ReactComponentProps<import("../../../oak-app-domain").EntityDict, "wechatMenu", true, {
applicationId: string;
menuId: string;
menuType: string;
}>) => import("react").ReactElement<any, string | import("react").JSXElementConstructor<any>>;
export default _default;

View File

@ -0,0 +1,58 @@
export default OakComponent({
isList: true,
entity: 'wechatMenu',
projection: {
id: 1,
menuConfig: 1,
applicationId: 1,
application: {
id: 1,
type: 1,
config: 1,
},
publishState: 1,
wechatPublicTagId: 1,
menuId: 1,
},
formData({ data: rows }) {
return {
id: rows?.[0]?.id,
config: rows?.[0]?.menuConfig,
totalConfig: rows?.[0]?.menuConfig,
};
},
filters: [
{
filter() {
const { applicationId } = this.props;
return {
applicationId,
wechatPublicTagId: {
$exists: false
}
};
},
}
],
properties: {
applicationId: '',
menuId: '',
menuType: '',
},
lifetimes: {
async ready() {
const { menuId, applicationId } = this.props;
if (!menuId) {
const menuConfig = await this.features.wechatMenu.getMenu({ applicationId: applicationId });
console.log(menuConfig);
this.addItem({
menuConfig: { button: menuConfig.menu.button },
applicationId,
publishState: 'wait',
menuId: menuConfig.menu.menuid
});
}
}
},
methods: {},
});

View File

@ -0,0 +1,67 @@
.container {
width: 100%;
.content {
display: flex;
flex-direction: row;
width: 100%;
.leftBar {
width: 300px;
margin-right: 25px;
}
.rightBar {
flex: 1;
}
}
}
.phone {
display: flex;
flex-direction: column;
width: 374px;
background: #f0f0f0;
border-radius: 8px;
.topBar {
display: flex;
flex-direction: row;
justify-content: space-between;
height: 30px;
margin: 8px 16px 12px 16px;
align-items: center;
.time {
font-size: 14px;
font-weight: bold;
}
.icons {
display: flex;
flex-direction: row;
}
}
.actionBar {
display: flex;
flex-direction: row;
justify-content: space-between;
margin: 0 10px;
}
.page {
height: 450px;
}
.bottomBar {
height: 68px;
display: flex;
flex-direction: column;
background: #fcfcfc;
.keyBoard {
width: 60px;
}
}
}

View File

@ -0,0 +1,14 @@
import { WechatPublicInstance } from 'oak-external-sdk';
import { WebComponentProps } from 'oak-frontend-base';
import { EntityDict } from "../../../oak-app-domain";
export default function Render(props: WebComponentProps<EntityDict, 'wechatMenu', true, {
id: string;
config: any;
totalConfig: any;
file: File;
wechatInstance: WechatPublicInstance;
errorIndex: number[];
oakId: string;
menuType: string;
applicationId: string;
}, {}>): import("react/jsx-runtime").JSX.Element | null;

View File

@ -0,0 +1,53 @@
import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
import { useState } from 'react';
import Style from './web.module.less';
import { Modal } from 'antd';
import Preview from '../preview';
import ActionPhone from '../actionPhone';
import MenuInfo from '../menuInfo';
export default function Render(props) {
const { data, methods } = props;
const { id, oakFullpath, config, wechatInstance, totalConfig, menuType, applicationId } = data;
const { updateItem, execute } = methods;
const [open, setOpen] = useState(false);
const [isPreview, setIsPreview] = useState(false);
const [selectedBtn, setSelectedBtn] = useState(0);
const [selectedSubBtn, setSelectedSubBtn] = useState(0);
const [currentIndex, setCurrentIndex] = useState(1);
const [errorIndex, setErrorIndex] = useState([]);
const changeConfig = (config) => {
updateItem({
menuConfig: config
}, id);
};
const changePublishState = (publishState) => {
updateItem({
publishState,
}, id);
};
const getSelectedBtn = (selectedBtn) => {
setSelectedBtn(selectedBtn);
};
const getSelectedSubBtn = (selectedSubBtn) => {
setSelectedSubBtn(selectedSubBtn);
};
const getCurrentIndex = (currentIndex) => {
setCurrentIndex(currentIndex);
};
const getErrorIndex = (errorIndex) => {
setErrorIndex(errorIndex);
};
const createMenu = async () => {
await execute();
};
const changeIsPreview = (isPreview) => {
setIsPreview(isPreview);
};
const getOpen = (open) => {
setOpen(open);
};
if (oakFullpath) {
return (_jsx("div", { className: Style.container, children: _jsxs("div", { className: Style.content, children: [_jsx("div", { className: Style.leftBar, children: _jsx(ActionPhone, { oakAutoUnmount: true, config: config, changeConfig: changeConfig, menuType: menuType, getSelectedBtn: getSelectedBtn, getSelectedSubBtn: getSelectedSubBtn, getCurrentIndex: getCurrentIndex, errorIndex: errorIndex, isPreview: isPreview, open: open }) }), _jsx("div", { className: Style.rightBar, children: _jsx(MenuInfo, { oakAutoUnmount: true, config: config, changeConfig: changeConfig, changePublishState: changePublishState, selectedBtn: selectedBtn, selectedSubBtn: selectedSubBtn, currentIndex: currentIndex, getErrorIndex: getErrorIndex, createMenu: createMenu, changeIsPreview: changeIsPreview, getOpen: getOpen, menuType: menuType, applicationId: applicationId }) }), _jsx(Modal, { title: '\u83DC\u5355\u9884\u89C8', open: isPreview, onCancel: () => setIsPreview(false), footer: null, width: 424, children: _jsx(Preview, { button: config?.button, applicationId: applicationId }) })] }) }));
}
return null;
}

View File

@ -0,0 +1,21 @@
/// <reference types="react" />
declare const _default: (props: import("oak-frontend-base").ReactComponentProps<import("../../../oak-app-domain").EntityDict, keyof import("../../../oak-app-domain").EntityDict, false, {
id: string;
config: any;
menuIndex: number;
changeConfig: (config: any) => void;
changePublishState: (publish: "wait" | "success" | "fail") => void;
getErrorIndex: (errorIndex: number[]) => void;
createMenu: () => Promise<void>;
selectedBtn: number;
selectedSubBtn: number;
currentIndex: number;
changeIsPreview: (isPreview: boolean) => void;
getOpen: (open: boolean) => void;
menuType: string;
applicationId: string;
changeMenuId: (menuId: number) => void;
deleteMenu: () => void;
menuId: number;
}>) => import("react").ReactElement<any, string | import("react").JSXElementConstructor<any>>;
export default _default;

View File

@ -0,0 +1,245 @@
export default OakComponent({
isList: false,
properties: {
id: '',
config: null,
menuIndex: 0,
changeConfig: (config) => undefined,
changePublishState: (publish) => undefined,
getErrorIndex: (errorIndex) => undefined,
createMenu: async () => undefined,
selectedBtn: 0,
selectedSubBtn: 0,
currentIndex: 1,
changeIsPreview: (isPreview) => undefined,
getOpen: (open) => undefined,
menuType: '',
applicationId: '',
changeMenuId: (menuId) => undefined,
deleteMenu: () => undefined,
menuId: null,
},
data: {},
methods: {
setConfig(index, content, currentIndex) {
const { config, changeConfig } = this.props;
if (typeof currentIndex === 'number') {
content.name = config.button[currentIndex].sub_button[index].name;
config.button[currentIndex].sub_button[index] = content;
changeConfig(config);
}
else {
content.name = config.button[index].name;
content.sub_button = [...config.button[index].sub_button];
config.button[index] = content;
changeConfig(config);
}
},
confirmName(menuName) {
if (Object.prototype.toString.call(menuName).slice(8, -1).toLowerCase() !== 'string') {
throw Error('param str type error ');
}
else if (!menuName) {
return '请输入菜单名称';
}
else if (!/^[\u4e00-\u9fa5a-zA-Z0-9]+$/.test(menuName)) {
return '字符串中包含除中文、数字、英文以外的字符!';
}
else if (menuName.replace(/[\u4e00-\u9fa5]/g, "**").length > 8) {
return '字符串长度超过限制!';
}
return '';
},
confirmSubName(menuName) {
if (Object.prototype.toString.call(menuName).slice(8, -1).toLowerCase() !== 'string') {
throw Error('param str type error ');
}
else if (!menuName) {
return '请输入子菜单名称';
}
else if (!/^[\u4e00-\u9fa5a-zA-Z0-9]+$/.test(menuName)) {
return '字符串中包含除中文、数字、英文以外的字符!';
}
else if (menuName.replace(/[\u4e00-\u9fa5]/g, "**").length > 16) {
return '字符串长度超过限制!';
}
return '';
},
editMenuName(index, name, currentIndex) {
const { config, changeConfig } = this.props;
if (typeof currentIndex === 'number') {
config.button[currentIndex].sub_button[index].name = name;
changeConfig(config);
}
else {
config.button[index].name = name;
changeConfig(config);
}
},
deleteMenuContent(index, currentIndex) {
const { config, changeConfig } = this.props;
if (typeof currentIndex === 'number') {
config.button[currentIndex].sub_button[index] = { name: config.button[currentIndex].sub_button[index].name };
changeConfig(config);
}
else {
config.button[index] = { name: config.button[index].name, sub_button: [...config.button[index].sub_button] };
changeConfig(config);
}
},
async getMaterialImgAndVoice(type, media_id) {
const { applicationId } = this.props;
return new Promise((resolve, reject) => {
this.features.wechatMenu.getMaterial({ applicationId: applicationId, type, media_id })
.then(file => {
let reader = new FileReader();
reader.readAsDataURL(file);
reader.onload = function (e) {
resolve(e.target?.result);
};
})
.catch(error => {
reject(error);
});
});
},
async getMaterialVideo(media_id) {
const { applicationId } = this.props;
const result = await this.features.wechatMenu.getMaterial({ applicationId: applicationId, type: 'video', media_id });
if (result && result.down_url) {
return { url: result.down_url, media_id };
}
},
decideMenuContentLabel(decidedMenuContent, type) {
if (!decidedMenuContent && type !== 'text') {
return '菜单内容';
}
else if (decidedMenuContent) {
switch (type) {
case 'news':
return '图文信息';
case 'image':
return '图片';
case 'voice':
return '音频';
case 'video':
return '视频';
default:
return '文字';
}
}
else {
return '文字'; // 默认值
}
},
async getArticle(article_id) {
const { applicationId } = this.props;
const result = await this.features.wechatMenu.getArticle({ applicationId: applicationId, article_id });
if (result && result.news_item) {
const modifiedResult = await Promise.all(result.news_item.map(async (ele) => {
const coverUrl = await this.getMaterialImgAndVoice('image', ele.thumb_media_id);
return {
...ele,
coverUrl
};
}));
return modifiedResult;
}
},
checkError(arr) {
const { getErrorIndex } = this.props;
const errorIndex = [];
arr.map((ele, index) => {
if (ele.sub_button && ele.sub_button.length > 0) {
ele.sub_button.map((ele, index2) => {
if (Object.keys(ele).length === 1 && ele.hasOwnProperty('name')) {
errorIndex.push((index + 1) * 10 + index2);
}
});
}
else {
if (Object.keys(ele).length === 2 && ele.hasOwnProperty('name')) {
console.log(index);
errorIndex.push(index);
}
}
});
this.setState({
errorIndex,
});
getErrorIndex(errorIndex);
return errorIndex;
},
async createMenu() {
const { applicationId, config, changeConfig, changePublishState, createMenu, menuType, changeMenuId } = this.props;
if (this.checkError(config.button).length === 0 && config.button.length > 0) {
changeConfig(config);
const removeSubTypeAndContent = (obj) => {
const { subType, content, ...newObj } = obj;
return newObj;
};
const menuConfig = config.button.map((item) => {
if (item.sub_button && item.sub_button.length > 0) {
const sub_button = item.sub_button.map(removeSubTypeAndContent);
return { ...removeSubTypeAndContent(item), sub_button };
}
else {
return removeSubTypeAndContent(item);
}
});
if (menuType === 'common') {
const result = await this.features.wechatMenu.createMenu({ applicationId: applicationId, menuConfig: { button: menuConfig } });
if (result.success) {
changePublishState('success');
}
else {
changePublishState('fail');
}
await createMenu();
}
else {
const button = { button: menuConfig, matchrule: config.matchrule };
const result = await this.features.wechatMenu.createConditionalMenu({ applicationId: applicationId, menuConfig: button });
if (result.success) {
changeMenuId(result.menuid);
changePublishState('success');
}
else {
changePublishState('fail');
}
await createMenu();
}
}
else {
if (config.button.length === 0) {
this.setMessage({
content: '请添加自定义菜单',
type: 'warning'
});
return;
}
if ((this.checkError(config.button).length > 0)) {
this.setMessage({
content: '请添加菜单消息',
type: 'warning'
});
return;
}
}
},
async deleteConditionalMenu() {
const { applicationId, deleteMenu, menuIndex, menuId, createMenu } = this.props;
const result = await this.features.wechatMenu.deleteConditionalMenu({ applicationId: applicationId, menuid: menuId });
if (result.success) {
deleteMenu();
await createMenu();
}
else {
this.setMessage({
type: 'error',
content: result.errmsg
});
}
}
}
});

View File

@ -0,0 +1,198 @@
.container {
width: 100%;
.editor {
display: flex;
flex-direction: row;
border: 1px solid #dbdbdb;
width: 600px;
position: relative;
}
.content {
padding: 40px;
border-bottom: 1px solid #EDEEEF;
background: #fcfcfc;
border-top-left-radius: 8px;
border-top-right-radius: 8px;
display: flex;
flex-direction: column;
.title {
font-size: 16px;
font-weight: bold;
margin-bottom: 32px;
}
.label {
width: 94px;
text-align: left;
}
.coverImage {
width: 300px;
display: flex;
flex-direction: row;
.img {
width: 100%;
object-fit: contain;
}
}
.fileCover {
width: 300px;
display: flex;
flex-direction: row;
align-items: center;
}
.buttonGroup {
margin-left: 10px;
display: flex;
flex-direction: column;
justify-content: center;
align-items: center;
width: 36px;
min-height: 36px;
border-radius: 18px;
background: #fcfcfc;
font-size: 18px;
padding: 3px;
box-shadow: 0 1px 6px #e4e8eb;
.buttonItem {
height: 30px;
width: 30px;
border-radius: 50%;
justify-content: center;
align-items: center;
display: flex;
cursor: pointer;
}
.buttonItem:hover {
background: #EDEEEF;
}
}
.menuContent {
display: flex;
flex-direction: row;
.item {
display: flex;
justify-content: center;
align-items: center;
padding: 10px;
background: #F6F7F8;
cursor: pointer;
}
.item:hover {
color: #1677FF;
}
}
.delete {
font-size: 14px;
color: #FF5557;
cursor: pointer;
width: 60px;
}
.delete:hover {
opacity: 0.7;
}
}
.actionBar {
display: flex;
justify-content: flex-end;
width: 100%;
background: #fcfcfc;
border-bottom-left-radius: 8px;
border-bottom-right-radius: 8px;
padding: 20px 40px 20px 40px;
}
.news {
width: 310px;
display: flex;
flex-direction: row;
border: 1px solid #dbdbdb;
border-radius: 4px;
.multiNews {
width: 100%;
display: flex;
flex-direction: column;
.cover {
width: 308px;
height: 130px;
border-top-left-radius: 8px;
border-top-right-radius: 8px;
.img {
object-fit: contain;
width: 100%;
height: 100%;
}
.articleTitle {
// color: #fff;
padding: 0 12px;
font-weight: bold;
font-size: 14px;
position: absolute;
top: 100px;
}
}
.newsItem {
display: flex;
flex-direction: row;
justify-content: space-between;
padding: 12px;
align-items: center;
.articleTitle {
width: 220px;
font-size: 14px;
color: #353535;
line-height: 48px;
border-bottom: 1px solid #dbdbdb;
font-weight: 500;
}
.imgCover {
object-fit: cover;
width: 48px;
height: 48px;
.img {
width: 100%;
height: 100%;
}
}
}
.newsItem:last-child {
.articleTitle {
border-bottom: 0;
}
}
}
.singleNews {
width: 100%;
display: flex;
flex-direction: column;
.cover {
width: 308px;
height: 130px;
border-top-left-radius: 4px;
border-top-right-radius: 4px;
.img {
object-fit: contain;
width: 100%;
height: 100%;
}
}
.articleTitle {
padding: 12px;
font-weight: bold;
font-size: 14px;
color: #353535;
font-weight: 500;
}
}
}
}

View File

@ -0,0 +1,37 @@
import { EntityDict } from "../../../oak-app-domain";
import { WebComponentProps } from 'oak-frontend-base';
export default function Render(props: WebComponentProps<EntityDict, keyof EntityDict, false, {
id: string;
config: any;
menuIndex: number;
file: File;
errorIndex: number[];
oakId: string;
menuType: string;
selectedBtn: number;
selectedSubBtn: number;
currentIndex: number;
getNewSelectedBtn: (selectedBtn: number) => void;
getNewSelectedSubBtn: (selectedSubBtn: number) => void;
getNewCurrentIndex: (currentIndex: number) => void;
changeIsPreview: (isPreview: boolean) => void;
getOpen: (open: boolean) => void;
applicationId: string;
menuId: number;
}, {
setConfig: (index: number, content: any, currentIndex?: number) => void;
confirmName: (menuName: string) => string;
confirmSubName: (menuName: string) => string;
toRight: (index: number) => void;
toLeft: (index: number) => void;
toUp: (currentIndex: number, index: number) => void;
toDown: (currentIndex: number, index: number) => void;
editMenuName: (index: number, name: string, currentIndex?: number) => void;
deleteMenuContent: (index: number, currentIndex?: number) => void;
getMaterialImgAndVoice: (type: string, media_id: string) => Promise<string>;
getMaterialVideo: (media_id: string) => void;
decideMenuContentLabel: (obj: any, type: 'news' | 'image' | 'video' | 'voice' | 'text') => string;
getArticle: (article_id: string) => void;
createMenu: () => void;
deleteConditionalMenu: () => void;
}>): import("react/jsx-runtime").JSX.Element;

View File

@ -0,0 +1,399 @@
import { jsx as _jsx, jsxs as _jsxs, Fragment as _Fragment } from "react/jsx-runtime";
import { useState, useEffect } from 'react';
import { Modal, Button, Space, Radio, Form, Input } from 'antd';
const { Search } = Input;
const { confirm } = Modal;
import Style from './web.module.less';
import { generateNewIdAsync } from 'oak-domain/lib/utils/uuid';
import { EyeOutlined, CheckOutlined, DeleteOutlined, DownloadOutlined, SwapOutlined, } from '@ant-design/icons';
import ShowNews from '../showNews';
import WechatMaterialLibrary from '../../wechatMaterialLibrary';
import SelectMiniprogram from '../selectMiniprogram';
import SelectArticle from '../selectArticle';
import TextClick from '../textClick';
export default function Render(props) {
const { data, methods } = props;
const { config, menuIndex, selectedBtn, selectedSubBtn, currentIndex, changeIsPreview, getOpen, menuType, applicationId, menuId } = data;
const { setConfig, confirmName, confirmSubName, editMenuName, deleteMenuContent, getMaterialImgAndVoice, getMaterialVideo, decideMenuContentLabel, getArticle, createMenu, deleteConditionalMenu } = methods;
const [msgType, setMsgType] = useState('sendMsg');
const [errorInfo, setErrorInfo] = useState('');
const [onlyOne, setOnlyOne] = useState(true);
const [menuName, setMenuName] = useState('');
const [open, setOpen] = useState(false);
const [type, setType] = useState('');
const [menuContent, setMenuContent] = useState(null);
const [decidedMenuContent, setDecidedMenuContent] = useState(null);
const [url, setUrl] = useState('');
const getUrl = (url) => {
setUrl(url);
};
const getMenuContent = (menuContent) => {
setMenuContent(menuContent);
if (msgType === 'miniprogram') {
if (selectedBtn > 0) {
setConfig(selectedBtn - 1, { type: 'miniprogram', url: menuContent.url, pagepath: menuContent.pagepath, appid: menuContent.appid });
}
else {
setConfig(selectedSubBtn - 1, { type: 'miniprogram', url: menuContent.url, pagepath: menuContent.pagepath, appid: menuContent.appid }, currentIndex);
}
}
};
const changeOpen = (open) => {
setOpen(open);
getOpen(open);
};
const getDecidedMenuContent = async (menuContent) => {
setDecidedMenuContent(menuContent);
if (selectedBtn > 0) {
setConfig(selectedBtn - 1, { type: 'click', key: await generateNewIdAsync(), subType: 'text', content: menuContent });
}
else {
setConfig(selectedSubBtn - 1, { type: 'click', key: await generateNewIdAsync(), subType: 'text', content: menuContent }, currentIndex);
}
};
useEffect(() => {
console.log(config);
if (config && config.button && config.button[0] && onlyOne) {
setMenuName(config.button[0].name);
setOnlyOne(false);
}
}, [config]);
useEffect(() => {
const fetchData = async (id, type) => {
if (type === 'news') {
setDecidedMenuContent({ content: { news_item: await getArticle(id) } });
}
if (type === 'video') {
setDecidedMenuContent(await getMaterialVideo(id));
}
if (type === 'image' || type === 'voice') {
setDecidedMenuContent({ url: await getMaterialImgAndVoice(type, id), media_id: id });
}
};
if (selectedBtn !== 0) {
const menuConfig = config.button[selectedBtn - 1];
setMenuName(menuConfig?.name);
if (menuConfig?.type === 'media_id') {
setUrl('');
setMsgType('sendMsg');
setType(menuConfig.subType);
if (menuConfig.subType === 'video') {
fetchData(menuConfig.media_id, 'video');
}
else {
fetchData(menuConfig.media_id, menuConfig.subType);
}
}
else if (menuConfig?.type === 'click') {
setUrl('');
setMsgType('sendMsg');
setType('text');
setDecidedMenuContent(menuConfig.content);
}
else if (menuConfig?.type === 'article_id') {
setUrl('');
setMsgType('sendMsg');
setType('news');
fetchData(menuConfig.article_id, 'news');
}
else if (menuConfig?.type === 'miniprogram') {
setUrl('');
setMsgType('miniprogram');
setMenuContent({
appid: menuConfig.appid,
url: menuConfig.url,
pagepath: menuConfig.pagepath
});
}
else if (menuConfig?.type === 'view') {
setMsgType('view');
setUrl(menuConfig.url);
}
else {
setUrl('');
setType('');
setMsgType('sendMsg');
setDecidedMenuContent(null);
setMenuContent(null);
}
}
}, [selectedBtn]);
useEffect(() => {
const fetchData = async (id, type) => {
if (type === 'news') {
setDecidedMenuContent({ content: { news_item: await getArticle(id) } });
}
if (type === 'video') {
setDecidedMenuContent(await getMaterialVideo(id));
}
if (type === 'image' || type === 'voice') {
setDecidedMenuContent({ url: await getMaterialImgAndVoice(type, id), media_id: id });
}
};
if (selectedSubBtn !== 0) {
const subMenuConfig = config.button[currentIndex]?.sub_button[selectedSubBtn - 1];
setMenuName(subMenuConfig?.name);
if (subMenuConfig?.type === 'media_id') {
setUrl('');
setMsgType('sendMsg');
setType(subMenuConfig.subType);
if (subMenuConfig.subType === 'video') {
fetchData(subMenuConfig.media_id, 'video');
}
else {
fetchData(subMenuConfig.media_id, subMenuConfig.subType);
}
}
else if (subMenuConfig?.type === 'click') {
setUrl('');
setMsgType('sendMsg');
setType('text');
setDecidedMenuContent(subMenuConfig.content);
}
else if (subMenuConfig?.type === 'article_id') {
setUrl('');
setMsgType('sendMsg');
setType('news');
fetchData(subMenuConfig?.article_id, 'news');
}
else if (subMenuConfig?.type === 'miniprogram') {
setUrl('');
setMsgType('miniprogram');
setMenuContent({
appid: subMenuConfig.appid,
url: subMenuConfig.url,
pagepath: subMenuConfig.pagepath
});
}
else if (subMenuConfig?.type === 'view') {
setMsgType('view');
setUrl(subMenuConfig.url);
}
else {
setType('');
setUrl('');
setMsgType('sendMsg');
setDecidedMenuContent(null);
setMenuContent(null);
}
}
}, [selectedSubBtn]);
useEffect(() => {
if (url && url.length > 0) {
if (selectedBtn > 0) {
setConfig(selectedBtn - 1, { type: 'view', url });
}
else {
setConfig(selectedSubBtn - 1, { type: 'view', url }, currentIndex);
}
}
}, [url]);
return (_jsx("div", { className: Style.container, children: config && config.button && config.button.length > 0 && (selectedBtn !== 0 || selectedSubBtn !== 0) ? (_jsxs("div", { className: Style.upsertMenu, children: [_jsxs("div", { className: Style.content, children: [_jsx("div", { className: Style.title, children: selectedSubBtn !== 0 ? '子菜单信息' : '菜单信息' }), _jsx("div", { style: { marginBottom: 32 }, children: _jsx(Form.Item, { label: _jsx("div", { className: Style.label, children: "\u540D\u79F0" }), colon: false, help: _jsxs("div", { children: [_jsx("div", { children: `仅支持中英文和数字,字数不超过${selectedSubBtn !== 0 ? 8 : 4}个汉字或${selectedSubBtn !== 0 ? 16 : 8}个字母。` }), errorInfo && _jsx("div", { style: { color: '#fa5151' }, children: errorInfo })] }), children: _jsx(Input, { style: { width: 340 }, onChange: (val) => {
setMenuName(val.target.value);
if (selectedSubBtn !== 0) {
setErrorInfo(confirmSubName(val.target.value));
if (!confirmSubName(val.target.value)) {
editMenuName(selectedSubBtn - 1, val.target.value, currentIndex);
}
}
else {
setErrorInfo(confirmName(val.target.value));
if (!confirmName(val.target.value)) {
editMenuName(selectedBtn - 1, val.target.value);
}
}
}, status: errorInfo ? 'error' : '', value: menuName }) }) }), config.button[currentIndex]?.sub_button?.length === 0 && selectedSubBtn === 0
|| selectedSubBtn > 0 ? (_jsxs(_Fragment, { children: [_jsx(Form.Item, { colon: false, label: _jsx("div", { className: Style.label, children: "\u6D88\u606F\u7C7B\u578B" }), children: _jsxs(Radio.Group, { value: msgType, onChange: (val) => setMsgType(val.target.value), children: [_jsx(Radio, { value: 'sendMsg', children: "\u53D1\u9001\u6D88\u606F" }), _jsx(Radio, { value: 'view', children: "\u8DF3\u8F6C\u9875\u9762" }), _jsx(Radio, { value: 'miniprogram', children: "\u8DF3\u8F6C\u5C0F\u7A0B\u5E8F" })] }) }), msgType === 'sendMsg' ? (_jsxs(_Fragment, { children: [_jsxs(Form.Item, { colon: false, label: _jsx("div", { className: Style.label, children: decideMenuContentLabel(decidedMenuContent, type) }), children: [!decidedMenuContent && type !== 'text' ? _jsxs("div", { className: Style.menuContent, children: [_jsx("div", { className: Style.item, onClick: () => {
setOpen(true);
getOpen(true);
setType('news');
}, children: "\u56FE\u6587\u4FE1\u606F" }), _jsx("div", { className: Style.item, onClick: () => {
setType('text');
}, children: "\u6587\u5B57" }), _jsx("div", { className: Style.item, onClick: () => {
setOpen(true);
getOpen(true);
setType('image');
}, children: "\u56FE\u7247" }), _jsx("div", { className: Style.item, onClick: () => {
setOpen(true);
getOpen(true);
setType('voice');
}, children: "\u97F3\u9891" }), _jsx("div", { className: Style.item, onClick: () => {
setOpen(true);
getOpen(true);
setType('video');
}, children: "\u89C6\u9891" })] })
: type === 'image' ?
_jsxs("div", { className: Style.coverImage, children: [_jsx("img", { className: Style.img, src: decidedMenuContent.url }), _jsxs("div", { className: Style.buttonGroup, children: [_jsx("div", { className: Style.buttonItem, onClick: () => {
const modal = confirm({
title: '确定删除该图片吗?',
content: '删除后不可恢复',
okText: '确定',
cancelText: '取消',
onOk: async (e) => {
modal.destroy();
setDecidedMenuContent(null);
if (selectedBtn > 0) {
deleteMenuContent(selectedBtn - 1);
}
else {
deleteMenuContent(selectedSubBtn - 1, currentIndex);
}
;
},
});
}, children: _jsx(DeleteOutlined, {}) }), _jsx("div", { className: Style.buttonItem, onClick: () => {
setOpen(true);
getOpen(true);
}, children: _jsx(SwapOutlined, {}) })] })] })
: type === 'voice' ?
_jsxs("div", { className: Style.fileCover, children: [_jsxs("a", { href: decidedMenuContent.url, download: true, style: { color: '#1677FF', cursor: 'pointer' }, children: [_jsx(DownloadOutlined, {}), decidedMenuContent.media_id] }), _jsxs("div", { className: Style.buttonGroup, children: [_jsx("div", { className: Style.buttonItem, onClick: () => {
const modal = confirm({
title: '确定删除该音频吗?',
content: '删除后不可恢复',
okText: '确定',
cancelText: '取消',
onOk: async (e) => {
modal.destroy();
setDecidedMenuContent(null);
if (selectedBtn > 0) {
deleteMenuContent(selectedBtn - 1);
}
else {
deleteMenuContent(selectedSubBtn - 1, currentIndex);
}
;
},
});
}, children: _jsx(DeleteOutlined, {}) }), _jsx("div", { className: Style.buttonItem, onClick: () => {
setOpen(true);
getOpen(true);
}, children: _jsx(SwapOutlined, {}) })] })] })
: type === 'video' ?
_jsxs("div", { className: Style.fileCover, children: [_jsxs("a", { href: decidedMenuContent.url, download: true, style: { color: '#1677FF', cursor: 'pointer' }, children: [_jsx(DownloadOutlined, {}), decidedMenuContent.media_id] }), _jsxs("div", { className: Style.buttonGroup, children: [_jsx("div", { className: Style.buttonItem, onClick: () => {
const modal = confirm({
title: '确定删除该视频吗?',
content: '删除后不可恢复',
okText: '确定',
cancelText: '取消',
onOk: async (e) => {
modal.destroy();
setDecidedMenuContent(null);
if (selectedBtn > 0) {
deleteMenuContent(selectedBtn - 1);
}
else {
deleteMenuContent(selectedSubBtn - 1, currentIndex);
}
;
},
});
}, children: _jsx(DeleteOutlined, {}) }), _jsx("div", { className: Style.buttonItem, onClick: () => {
setOpen(true);
getOpen(true);
}, children: _jsx(SwapOutlined, {}) })] })] })
: type === 'news' ?
_jsxs("div", { className: Style.news, children: [_jsx(ShowNews, { news: decidedMenuContent?.content?.news_item, oakAutoUnmount: false }), _jsxs("div", { className: Style.buttonGroup, style: { height: '100%' }, children: [_jsx("div", { className: Style.buttonItem, onClick: () => {
const modal = confirm({
title: '确定删除该图文信息吗?',
content: '删除后不可恢复',
okText: '确定',
cancelText: '取消',
onOk: async (e) => {
modal.destroy();
setDecidedMenuContent(null);
if (selectedBtn > 0) {
deleteMenuContent(selectedBtn - 1);
}
else {
deleteMenuContent(selectedSubBtn - 1, currentIndex);
}
;
},
});
}, children: _jsx(DeleteOutlined, {}) }), _jsx("div", { className: Style.buttonItem, onClick: () => {
setOpen(true);
getOpen(true);
}, children: _jsx(SwapOutlined, {}) })] })] })
: null, type === 'text' &&
_jsxs("div", { className: Style.editor, children: [_jsx(TextClick, { oakAutoUnmount: true, value: decidedMenuContent, getDecidedMenuContent: getDecidedMenuContent }), _jsx("div", { className: Style.buttonGroup, style: { height: 36, position: 'absolute', right: -50 }, children: _jsx("div", { className: Style.buttonItem, onClick: () => {
const modal = confirm({
title: '确定删除该文字吗?',
content: '删除后不可恢复',
okText: '确定',
cancelText: '取消',
onOk: async (e) => {
modal.destroy();
setType('news');
setDecidedMenuContent(null);
if (selectedBtn > 0) {
deleteMenuContent(selectedBtn - 1);
}
else {
deleteMenuContent(selectedSubBtn - 1, currentIndex);
}
},
});
}, children: _jsx(DeleteOutlined, {}) }) })] })] }), _jsx(Modal, { open: open, footer: _jsxs(Space, { children: [_jsx(Button, { type: 'primary', disabled: !menuContent, onClick: () => {
setOpen(false);
getOpen(false);
setDecidedMenuContent(menuContent);
if (selectedBtn > 0) {
if (type !== 'news') {
if (type === 'image') {
setConfig(selectedBtn - 1, { type: 'media_id', media_id: menuContent.media_id, subType: 'image' });
}
if (type === 'voice') {
setConfig(selectedBtn - 1, { type: 'media_id', media_id: menuContent.media_id, subType: 'voice' });
}
if (type === 'video') {
setConfig(selectedBtn - 1, { type: 'media_id', media_id: menuContent.media_id, subType: 'video' });
}
}
else {
setConfig(selectedBtn - 1, { type: 'article_id', article_id: menuContent.article_id });
}
}
else {
if (type !== 'news') {
if (type === 'image') {
setConfig(selectedSubBtn - 1, { type: 'media_id', media_id: menuContent.media_id, subType: 'image' }, currentIndex);
}
if (type === 'voice') {
setConfig(selectedSubBtn - 1, { type: 'media_id', media_id: menuContent.media_id, subType: 'voice' }, currentIndex);
}
if (type === 'video') {
setConfig(selectedSubBtn - 1, { type: 'media_id', media_id: menuContent.media_id, subType: 'video' }, currentIndex);
}
}
else {
setConfig(selectedSubBtn - 1, { type: 'article_id', article_id: menuContent.article_id }, currentIndex);
}
}
}, children: "\u786E\u5B9A" }), _jsx(Button, { type: 'default', onClick: () => {
setOpen(false);
getOpen(false);
setMenuContent(null);
}, children: "\u53D6\u6D88" })] }), onCancel: () => {
setOpen(false);
getOpen(false);
setMenuContent(null);
}, destroyOnClose: true, width: 960, children: _jsx(WechatMaterialLibrary, { oakAutoUnmount: true, type: type, getMenuContent: getMenuContent, applicationId: applicationId }) })] })) : msgType === 'view' ? (_jsxs(Form.Item, { colon: false, label: _jsx("div", { className: Style.label, children: "\u7F51\u9875\u94FE\u63A5" }), children: [_jsxs("div", { style: { display: 'flex', flexDirection: 'column' }, children: [_jsx(Input, { placeholder: '\u516C\u4F17\u53F7\u94FE\u63A5', style: { width: 340 }, value: url, onChange: (val) => setUrl(val.target.value) }), _jsx("a", { style: { padding: '10px 0' }, onClick: () => { setOpen(true); getOpen(true); }, children: "\u9009\u62E9\u56FE\u6587\u94FE\u63A5" })] }), _jsx(Modal, { open: open, footer: null, title: '选择图文链接', onCancel: () => { setOpen(false); getOpen(false); }, width: 600, children: _jsx(SelectArticle, { oakAutoUnmount: true, changeOpen: changeOpen, getUrl: getUrl, applicationId: applicationId }) })] })) : (_jsxs(Form.Item, { colon: false, label: _jsx("div", { className: Style.label, children: "\u5C0F\u7A0B\u5E8F" }), children: [_jsx(Button, { onClick: () => {
setOpen(true);
getOpen(true);
}, children: "\u9009\u62E9\u5C0F\u7A0B\u5E8F" }), menuContent && menuContent.appid && _jsx("div", { children: menuContent.appid }), _jsx(Modal, { title: '添加小程序', open: open, footer: null, onCancel: () => { setOpen(false); getOpen(false); }, children: _jsx(SelectMiniprogram, { oakAutoUnmount: true, getMenuContent: getMenuContent, changeOpen: changeOpen }) })] }))] })) : (null)] }), _jsx("div", { className: Style.actionBar, children: _jsxs(Space, { children: [_jsxs(Button, { onClick: () => changeIsPreview(true), children: [_jsx(EyeOutlined, {}), "\u9884\u89C8"] }), _jsxs(Button, { type: 'primary', onClick: async () => {
createMenu();
}, children: [_jsx(CheckOutlined, {}), "\u53D1\u5E03"] }), menuType === 'conditional' && config && menuId && _jsxs(Button, { type: 'primary', danger: true, onClick: () => {
const modal = confirm({
title: '确定删除该个性化菜单吗?',
content: '删除后不可恢复',
okText: '确定',
cancelText: '取消',
onOk: async (e) => {
await deleteConditionalMenu();
modal.destroy();
},
});
}, children: [_jsx(DeleteOutlined, {}), "\u5220\u9664"] })] }) })] })) : (_jsxs("div", { className: Style.empty, children: [_jsx("div", { className: Style.content, children: "\u4F60\u672A\u6DFB\u52A0\u81EA\u5B9A\u4E49\u83DC\u5355\uFF0C\u70B9\u51FB\u5DE6\u4FA7\u6DFB\u52A0\u83DC\u5355\u4E3A\u516C\u4F17\u53F7\u521B\u5EFA\u83DC\u5355\u680F\u3002" }), _jsx("div", { className: Style.actionBar, children: _jsxs(Space, { children: [_jsxs(Button, { onClick: () => changeIsPreview(true), children: [_jsx(EyeOutlined, {}), "\u9884\u89C8"] }), _jsxs(Button, { type: 'primary', onClick: async () => {
createMenu();
}, children: [_jsx(CheckOutlined, {}), "\u53D1\u5E03"] })] }) })] })) }));
}

View File

@ -0,0 +1,7 @@
/// <reference types="react" />
declare const _default: (props: import("oak-frontend-base").ReactComponentProps<import("../../../oak-app-domain").EntityDict, keyof import("../../../oak-app-domain").EntityDict, false, {
button: any[];
news: any[];
applicationId: string;
}>) => import("react").ReactElement<any, string | import("react").JSXElementConstructor<any>>;
export default _default;

View File

@ -0,0 +1,43 @@
export default OakComponent({
isList: false,
properties: {
button: [],
news: [],
applicationId: '',
},
data: {},
methods: {
async getMaterialImgAndVoice(type, media_id) {
const { applicationId } = this.props;
const imgFile = await this.features.wechatMenu.getMaterial({ applicationId: applicationId, type, media_id });
return new Promise((resolve) => {
const reader = new FileReader();
reader.readAsDataURL(imgFile);
reader.onload = function (e) {
resolve(e.target?.result);
};
});
},
async getArticle(article_id) {
const { applicationId } = this.props;
const result = await this.features.wechatMenu.getArticle({ applicationId: applicationId, article_id });
if (result && result.news_item) {
const modifiedResult = await Promise.all(result.news_item.map(async (ele) => {
const coverUrl = await this.getMaterialImgAndVoice('image', ele.thumb_media_id);
return {
...ele,
coverUrl
};
}));
return modifiedResult;
}
},
async getMaterialVideo(media_id) {
const { applicationId } = this.props;
const result = await this.features.wechatMenu.getMaterial({ applicationId: applicationId, type: 'video', media_id });
if (result && result.down_url) {
return { url: result.down_url, media_id };
}
},
}
});

View File

@ -0,0 +1,114 @@
.container {
.phone {
display: flex;
flex-direction: column;
width: 374px;
background: #e0e0e0;
border-radius: 8px;
.topBar {
display: flex;
flex-direction: row;
justify-content: space-between;
height: 30px;
margin: 8px 16px 12px 16px;
align-items: center;
.time {
font-size: 14px;
font-weight: bold;
}
.icons {
display: flex;
flex-direction: row;
}
}
.actionBar {
display: flex;
flex-direction: row;
justify-content: space-between;
margin: 0 10px;
}
.page {
width: 394px;
height: 450px;
overflow-y: auto;
padding: 10px 0;
.img {
max-width: 80%;
margin-top: 10px;
margin-left: 20px;
}
.news {
max-width: 80%;
margin-top: 10px;
margin-left: 20px;
}
.msg {
max-width: 80%;
width: max-content;
min-height: 30px;
margin-left: 20px;
background: #fff;
border-radius: 4px;
margin-top: 10px;
padding: 4px 10px;
position: relative;
border-left: 1px solid #fff;
.editor {
:global {
p {
margin: 0 !important;
}
div {
padding: 0 !important;
}
}
}
}
.msg::before {
content: ''; /* 伪元素的内容为空 */
position: absolute;
top: 50%; /* 将箭头垂直居中 */
left: -10px; /* 控制箭头的位置 */
border: 5px solid transparent; /* 创建一个透明的矩形 */
border-right-color: #fff; /* 设置矩形的右侧颜色 */
transform: translateY(-50%); /* 调整垂直居中位置 */
}
}
.bottomBar {
height: 38px;
display: flex;
flex-direction: row;
border-bottom-left-radius: 8px;
border-bottom-right-radius: 8px;
background: #f0f0f0;
.keyBoard {
width: 60px;
height: 100%;
}
.buttonList {
width: 100%;
height: 100%;
display: flex;
flex-direction: row;
.button {
display: flex;
align-items: center;
justify-content: center;
flex: 1;
border-left: 1px solid #d0d0d0;
padding: 7px 0;
cursor: pointer;
}
.button:hover {
background-color: #d0d0d0;
}
}
}
}
}

View File

@ -0,0 +1,14 @@
import { EntityDict } from "../../../oak-app-domain";
import { WebComponentProps } from 'oak-frontend-base';
import { WechatPublicInstance } from 'oak-external-sdk';
export default function Render(props: WebComponentProps<EntityDict, keyof EntityDict, false, {
button: any[];
wechatInstance: WechatPublicInstance;
}, {
getMaterialImgAndVoice: (type: 'image' | 'voice', media_id: string) => Promise<string>;
getArticle: (article_id: string) => Promise<any[]>;
getMaterialVideo: (media_id: string) => {
url: string;
media_id: string;
};
}>): import("react/jsx-runtime").JSX.Element;

View File

@ -0,0 +1,88 @@
import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
import { useState } from 'react';
import { Dropdown } from 'antd';
import { WifiOutlined, LeftOutlined, UserOutlined, MenuOutlined } from '@ant-design/icons';
import Style from './web.module.less';
import { Editor } from '@wangeditor/editor-for-react';
import ShowNews from '../showNews';
export default function Render(props) {
const { button } = props.data;
const { getMaterialImgAndVoice, getArticle, getMaterialVideo } = props.methods;
const [sendMsg, setSendMsg] = useState([]);
const editorConfig = {
readOnly: true,
autoFocus: true,
scroll: false,
};
const onClick = ({ key }) => {
const index = Math.floor(Number(key) / 10);
const index2 = Number(key) % 10;
menuAction(button[index].sub_button[index2]);
};
const menuAction = async (menu) => {
if (menu.type === 'view' && menu.url) {
window.open(menu.url);
return;
}
if (menu.type === 'miniprogram' && menu.url) {
setSendMsg([...sendMsg, { type: 'miniprogram', content: '不支持查看小程序,请前往微信公众号平台查看' }]);
return;
}
if (menu.subType === 'text' && menu.content) {
setSendMsg([...sendMsg, { type: 'text', content: menu.content }]);
return;
}
if (menu.subType === 'image' && menu.media_id) {
setSendMsg([...sendMsg, { type: 'image', content: await getMaterialImgAndVoice('image', menu.media_id) }]);
return;
}
if (menu.type === 'article_id' && menu.article_id) {
setSendMsg([...sendMsg, { type: 'article_id', content: await getArticle(menu.article_id) }]);
return;
}
if (menu.subType === 'voice' && menu.media_id) {
setSendMsg([...sendMsg, { type: 'voice', content: { url: await getMaterialImgAndVoice('voice', menu.media_id), media_id: menu.media_id } }]);
return;
}
if (menu.subType === 'video' && menu.media_id) {
setSendMsg([...sendMsg, { type: 'video', content: { url: await getMaterialVideo(menu.media_id).url, media_id: menu.media_id } }]);
return;
}
};
return (_jsx("div", { className: Style.container, children: _jsxs("div", { className: Style.phone, children: [_jsxs("div", { className: Style.topBar, children: [_jsx("div", { className: Style.time, children: "1:21" }), _jsx("div", { className: Style.icons, children: _jsx(WifiOutlined, { style: { fontSize: 14 } }) })] }), _jsxs("div", { className: Style.actionBar, children: [_jsx(LeftOutlined, { style: { fontSize: 20 } }), _jsx(UserOutlined, { style: { fontSize: 20 } })] }), _jsx("div", { className: Style.page, children: (sendMsg && sendMsg.length > 0) &&
sendMsg.map((ele) => {
if (ele.type === 'text') {
return _jsx("div", { className: Style.msg, children: _jsx(Editor, { defaultConfig: editorConfig, value: ele.content, mode: "default", className: Style.editor }) });
}
else if (ele.type === 'image') {
return _jsx("img", { src: ele.content, className: Style.img });
}
else if (ele.type === 'article_id') {
return _jsx("div", { className: Style.news, children: _jsx(ShowNews, { news: ele.content }) });
}
else if (ele.type === 'voice') {
return _jsx("div", { className: Style.msg, children: _jsx("a", { style: { color: '#1677ff' }, href: ele.content.url, download: true, children: ele.content.media_id }) });
}
else if (ele.type === 'video') {
return _jsx("div", { className: Style.msg, children: _jsx("a", { style: { color: '#1677ff' }, href: ele.content.url, download: true, children: ele.content.media_id }) });
}
else if (ele.type === 'miniprogram') {
return _jsx("div", { className: Style.msg, children: ele.content });
}
}) }), _jsxs("div", { className: Style.bottomBar, children: [_jsx("div", { className: Style.keyBoard }), _jsx("div", { className: Style.buttonList, children: button?.map((ele, index) => {
if (ele.sub_button && ele.sub_button.length > 0) {
const items = ele.sub_button.map((sub, index2) => {
return {
label: sub.name,
key: `${index * 10 + index2}`,
};
});
return _jsx(Dropdown, { arrow: false, menu: { items, onClick }, placement: 'top', children: _jsxs("div", { className: Style.button, children: [_jsx(MenuOutlined, { style: { fontSize: 12, color: '#d0d0d0' } }), _jsx("div", { className: Style.buttonName, style: { marginLeft: 5 }, children: ele.name })] }) });
}
else {
return _jsx("div", { className: Style.button, onClick: () => {
menuAction(ele);
}, children: _jsx("div", { className: Style.buttonName, children: ele.name }) });
}
}) })] })] }) }));
}

View File

@ -0,0 +1,7 @@
/// <reference types="react" />
declare const _default: (props: import("oak-frontend-base").ReactComponentProps<import("../../../oak-app-domain").EntityDict, keyof import("../../../oak-app-domain").EntityDict, false, {
getUrl: (url: string) => void;
changeOpen: (open: boolean) => void;
applicationId: string;
}>) => import("react").ReactElement<any, string | import("react").JSXElementConstructor<any>>;
export default _default;

View File

@ -0,0 +1,54 @@
export default OakComponent({
isList: false,
properties: {
getUrl: (url) => undefined,
changeOpen: (open) => undefined,
applicationId: '',
},
lifetimes: {
async ready() {
const { applicationId } = this.props;
if (applicationId) {
this.getArticleList(1);
}
}
},
methods: {
async getArticleList(page) {
const { applicationId } = this.props;
const offset = (page - 1) * 10;
const result = await this.features.wechatMenu.batchGetArticle({ applicationId: applicationId, offset, count: 10, noContent: 0 });
const modifiedResult = await Promise.all(result.item.map(async (ele) => {
const news_item = await Promise.all(ele.content.news_item.map(async (ele2) => {
const coverUrl = await this.getMaterialImg(ele2.thumb_media_id);
return {
...ele2,
coverUrl
};
}));
return {
...ele,
content: {
...ele.content,
news_item
}
};
}));
this.setState({
materials: modifiedResult,
total: result.total_count,
});
},
async getMaterialImg(media_id) {
const { applicationId } = this.props;
const imgFile = await this.features.wechatMenu.getMaterial({ applicationId: applicationId, type: 'image', media_id });
return new Promise((resolve) => {
const reader = new FileReader();
reader.readAsDataURL(imgFile);
reader.onload = function (e) {
resolve(e.target?.result);
};
});
}
}
});

View File

@ -0,0 +1,40 @@
.container {
display: flex;
flex-direction: column;
width: 100%;
.title {
font-size: 16px;
}
.upload {
display: flex;
flex-direction: row;
justify-content: flex-end;
align-items: center;
margin: 20px 0 0 0;
.help {
color: #B1B2B3;
margin-right: 10px;
}
}
.list {
margin-top: 20px;
}
}
:global {
.ant-select-selector {
padding: 0 !important;
}
}
.select {
.selectItem {
cursor: pointer;
width: 100%;
display: flex;
justify-content: center;
line-height: 30px;
}
.selectItem:hover {
background: #f5f5f5;
}
}

View File

@ -0,0 +1,12 @@
import { EntityDict } from "../../../oak-app-domain";
import { WebComponentProps } from 'oak-frontend-base';
export default function Render(props: WebComponentProps<EntityDict, keyof EntityDict, true, {
type: string;
materials: any[];
total: number;
getUrl: (url: string) => void;
changeOpen: (open: boolean) => void;
}, {
getArticleList: (page: number) => void;
upload: (media: FormData, description?: FormData) => boolean;
}>): import("react/jsx-runtime").JSX.Element;

View File

@ -0,0 +1,88 @@
import { jsx as _jsx, Fragment as _Fragment, jsxs as _jsxs } from "react/jsx-runtime";
import { useState, useRef } from 'react';
import { Button, Table, Space, Input, Popover, Select } from 'antd';
const { TextArea } = Input;
import Style from './web.module.less';
import dayjs from 'dayjs';
import ShowNews from '../showNews';
export default function Render(props) {
const { changeOpen, materials, total, getUrl } = props.data;
const { getArticleList, setMessage, upload } = props.methods;
const [currentPage, setCurrentPage] = useState(1);
const [url, setUrl] = useState('');
const [selectedRowKeys, setSelectedRowKeys] = useState([]);
const selectRef = useRef(null);
const columns = [
{
dataIndex: 'serial-number',
title: '序号',
render: (value, record, index) => {
return index + 1;
},
width: 100
},
{
dataIndex: 'url',
title: '图文链接',
render: (value, record, index) => {
if (record.content.news_item.length > 1) {
const urlList = record.content.news_item.map((ele) => {
return ele.url;
});
return (_jsx("div", { children: _jsx(Select, { ref: selectRef, style: { width: 160 }, bordered: false, value: urlList.includes(url) ? url : '请选择一篇文章', dropdownRender: () => _jsx("div", { className: Style.select, children: record.content.news_item.map((ele, index) => (_jsx(Popover, { content: _jsx("div", { style: { padding: 12 }, children: _jsx(ShowNews, { oakAutoUnmount: true, news: record.content.news_item.filter((ele, index2) => index === index2) }) }), placement: 'right', children: _jsx("div", { className: Style.selectItem, onClick: () => {
selectRef.current.blur();
setUrl(ele.url);
setSelectedRowKeys([record.article_id]);
}, children: ele.url }) }))) }) }) }));
}
else {
return (_jsx("div", { children: _jsx("div", { children: record.content.news_item[0].url }) }));
}
}
},
{
dataIndex: 'update_time',
title: '更新时间',
render: (value, record, index) => {
return _jsx(_Fragment, { children: dayjs(value).format('YYYY-MM-DD HH:mm') });
}
},
{
dataIndex: 'op',
title: '操作',
render: (value, record, index) => {
return _jsx(Popover, { content: _jsx("div", { style: { padding: 12 }, children: _jsx(ShowNews, { oakAutoUnmount: true, news: record.content.news_item }) }), children: _jsx("div", { style: { cursor: 'pointer', color: '#1677ff' }, children: "\u9884\u89C8" }) });
}
}
];
return (_jsxs("div", { className: Style.container, children: [_jsx("div", { className: Style.list, children: _jsx(Table, { dataSource: materials, columns: columns, rowKey: "article_id", pagination: {
total: total,
pageSize: 10,
current: currentPage,
onChange: (page, pageSize) => {
setCurrentPage(page);
getArticleList(page);
},
}, rowSelection: {
type: 'radio',
selectedRowKeys: selectedRowKeys,
onSelect: (record) => {
if (record.content.news_item.length > 1) {
return;
}
else {
setUrl(record.content.news_item[0].url);
}
},
onChange: (selectedRowKeys) => {
setSelectedRowKeys(selectedRowKeys);
}
} }) }), _jsxs(Space, { style: { display: 'flex', justifyContent: 'center' }, children: [_jsx(Button, { disabled: !url, type: 'primary', onClick: () => {
getUrl(url);
setUrl('');
changeOpen(false);
}, children: "\u786E\u5B9A" }), _jsx(Button, { onClick: () => {
setUrl('');
changeOpen(false);
}, children: "\u53D6\u6D88" })] })] }));
}

View File

@ -0,0 +1,6 @@
/// <reference types="react" />
declare const _default: (props: import("oak-frontend-base").ReactComponentProps<import("../../../oak-app-domain").EntityDict, keyof import("../../../oak-app-domain").EntityDict, false, {
getMenuContent: (menuContent: any) => void;
changeOpen: (open: boolean) => void;
}>) => import("react").ReactElement<any, string | import("react").JSXElementConstructor<any>>;
export default _default;

View File

@ -0,0 +1,9 @@
export default OakComponent({
isList: false,
properties: {
getMenuContent: (menuContent) => undefined,
changeOpen: (open) => undefined,
},
lifetimes: {},
methods: {}
});

View File

@ -0,0 +1,3 @@
.container {
width: 100%;
}

View File

@ -0,0 +1,6 @@
import { EntityDict } from "../../../oak-app-domain";
import { WebComponentProps } from 'oak-frontend-base';
export default function Render(props: WebComponentProps<EntityDict, keyof EntityDict, true, {
getMenuContent: (menuContent: any) => void;
changeOpen: (open: boolean) => void;
}, {}>): import("react/jsx-runtime").JSX.Element;

View File

@ -0,0 +1,47 @@
import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
import { useState } from 'react';
import { Button, Space, Form, Input } from 'antd';
import Style from './web.module.less';
export default function Render(props) {
const { getMenuContent, changeOpen } = props.data;
const { setMessage } = props.methods;
const [appid, setAppid] = useState('');
const [url, setUrl] = useState('');
const [pagepath, setPagepath] = useState('');
return (_jsxs("div", { className: Style.container, children: [_jsx(Form.Item, { required: true, label: 'appid', labelAlign: 'right', labelCol: { span: 6 }, children: _jsx(Input, { placeholder: '\u5C0F\u7A0B\u5E8F\u7684appid', onChange: (val) => {
setAppid(val.target.value);
}, value: appid }) }), _jsx(Form.Item, { required: true, label: 'url', labelAlign: 'right', labelCol: { span: 6 }, children: _jsx(Input, { placeholder: '\u5C0F\u7A0B\u5E8F\u7684\u7F51\u9875\u94FE\u63A5', onChange: (val) => {
setUrl(val.target.value);
}, value: url }) }), _jsx(Form.Item, { required: true, label: 'pagepath', labelAlign: 'right', labelCol: { span: 6 }, children: _jsx(Input, { placeholder: '\u5C0F\u7A0B\u5E8F\u7684\u9875\u9762\u8DEF\u5F84', onChange: (val) => {
setPagepath(val.target.value);
}, value: pagepath }) }), _jsxs(Space, { style: { display: 'flex', justifyContent: 'center' }, children: [_jsx(Button, { type: 'primary', onClick: () => {
if (!appid) {
setMessage({
type: 'warning',
content: '请输入小程序appid'
});
return;
}
if (!url) {
setMessage({
type: 'warning',
content: '请输入小程序网页链接'
});
return;
}
if (!pagepath) {
setMessage({
type: 'warning',
content: '请输入小程序页面路径'
});
return;
}
getMenuContent({ appid, url, pagepath });
setAppid('');
setPagepath('');
setUrl('');
changeOpen(false);
}, children: "\u786E\u5B9A" }), _jsx(Button, { onClick: () => {
changeOpen(false);
}, children: "\u53D6\u6D88" })] })] }));
}

View File

@ -0,0 +1,5 @@
/// <reference types="react" />
declare const _default: (props: import("oak-frontend-base").ReactComponentProps<import("../../../oak-app-domain").EntityDict, keyof import("../../../oak-app-domain").EntityDict, false, {
news: any[];
}>) => import("react").ReactElement<any, string | import("react").JSXElementConstructor<any>>;
export default _default;

View File

@ -0,0 +1,8 @@
export default OakComponent({
isList: false,
properties: {
news: [],
},
data: {},
methods: {}
});

View File

@ -0,0 +1,86 @@
.container {
width: 310px;
display: flex;
flex-direction: row;
border: 1px solid #dbdbdb;
border-radius: 4px;
background: #fff;
.multiNews {
width: 100%;
display: flex;
flex-direction: column;
.cover {
width: 308px;
height: 130px;
border-top-left-radius: 8px;
border-top-right-radius: 8px;
position: relative;
.img {
object-fit: contain;
width: 100%;
height: 100%;
}
.articleTitle {
// color: #fff;
padding: 0 12px;
font-weight: bold;
font-size: 14px;
position: absolute;
top: 100px;
}
}
.newsItem {
display: flex;
flex-direction: row;
justify-content: space-between;
padding: 12px;
align-items: center;
.articleTitle {
width: 220px;
font-size: 14px;
color: #353535;
line-height: 48px;
border-bottom: 1px solid #dbdbdb;
font-weight: 500;
}
.imgCover {
object-fit: cover;
width: 48px;
height: 48px;
.img {
width: 100%;
height: 100%;
}
}
}
.newsItem:last-child {
.articleTitle {
border-bottom: 0;
}
}
}
.singleNews {
width: 100%;
display: flex;
flex-direction: column;
.cover {
width: 308px;
height: 130px;
border-top-left-radius: 4px;
border-top-right-radius: 4px;
.img {
object-fit: contain;
width: 100%;
height: 100%;
}
}
.articleTitle {
padding: 12px;
font-weight: bold;
font-size: 14px;
color: #353535;
font-weight: 500;
}
}
}

View File

@ -0,0 +1,5 @@
import { EntityDict } from "../../../oak-app-domain";
import { WebComponentProps } from 'oak-frontend-base';
export default function Render(props: WebComponentProps<EntityDict, keyof EntityDict, false, {
news: any[];
}, {}>): import("react/jsx-runtime").JSX.Element;

View File

@ -0,0 +1,16 @@
import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
import Style from './web.module.less';
export default function Render(props) {
const { news } = props.data;
return (_jsx("div", { className: Style.container, children: news && news.length > 1 ?
_jsx("div", { className: Style.multiNews, children: news.map((ele, index) => {
if (index === 0) {
return (_jsxs("div", { className: Style.cover, children: [_jsx("img", { className: Style.img, src: ele.coverUrl }), _jsx("div", { className: Style.articleTitle, children: ele.title })] }));
}
else {
return (_jsxs("div", { className: Style.newsItem, children: [_jsx("div", { className: Style.articleTitle, children: ele.title }), _jsx("div", { className: Style.imgCover, children: _jsx("img", { className: Style.img, src: ele.coverUrl }) })] }));
}
}) })
:
_jsxs("div", { className: Style.singleNews, children: [_jsx("div", { className: Style.cover, children: _jsx("img", { className: Style.img, src: news?.[0]?.coverUrl }) }), _jsx("div", { className: Style.articleTitle, children: news?.[0]?.title })] }) }));
}

View File

@ -0,0 +1,10 @@
/// <reference types="react" />
declare const _default: (props: import("oak-frontend-base").ReactComponentProps<import("../../../oak-app-domain").EntityDict, "wechatPublicTag", true, {
news: any[];
applicationId: string;
getTag: (data: {
id: string;
name: string;
}) => void;
}>) => import("react").ReactElement<any, string | import("react").JSXElementConstructor<any>>;
export default _default;

View File

@ -0,0 +1,38 @@
export default OakComponent({
isList: true,
entity: 'wechatPublicTag',
projection: {
id: 1,
applicationId: 1,
text: 1,
wechatId: 1,
},
formData({ data: rows }) {
return {
rows,
};
},
pagination: {
pageSize: 20,
currentPage: 1,
more: false,
},
lifetimes: {},
filters: [
{
filter() {
const { applicationId } = this.props;
return {
applicationId
};
},
}
],
properties: {
news: [],
applicationId: '',
getTag: (data) => undefined,
},
data: {},
methods: {}
});

View File

@ -0,0 +1,9 @@
import { EntityDict } from "../../../oak-app-domain";
import { WebComponentProps } from 'oak-frontend-base';
export default function Render(props: WebComponentProps<EntityDict, 'wechatPublicTag', true, {
rows: EntityDict['wechatPublicTag']['Schema'][];
getTag: (data: {
id: string;
name: string;
}) => void;
}, {}>): import("react/jsx-runtime").JSX.Element;

View File

@ -0,0 +1,30 @@
import { jsx as _jsx } from "react/jsx-runtime";
import { useState } from 'react';
import { Table } from 'antd';
import Style from './web.module.less';
export default function Render(props) {
const { rows, oakLoading, getTag } = props.data;
const [selectedRowKeys, setSelectedRowKeys] = useState([]);
return (_jsx("div", { className: Style.container, children: _jsx(Table, { loading: oakLoading, dataSource: rows || [], rowKey: "id", columns: [
{
dataIndex: 'text',
title: '标签名',
},
], rowSelection: {
type: 'radio',
onSelect: (record) => {
getTag({ id: `${record.wechatId}`, name: record.text });
},
selectedRowKeys: selectedRowKeys,
onChange: (selectedRowKeys) => {
setSelectedRowKeys(selectedRowKeys);
}
}, onRow: (record) => {
return {
onClick: () => {
setSelectedRowKeys([record.id]);
getTag({ id: `${record.wechatId}`, name: record.text });
}
};
}, pagination: false }) }));
}

View File

@ -0,0 +1,6 @@
/// <reference types="react" />
declare const _default: (props: import("oak-frontend-base").ReactComponentProps<import("../../../oak-app-domain").EntityDict, keyof import("../../../oak-app-domain").EntityDict, false, {
value: string;
getDecidedMenuContent: (menuContent: any) => void;
}>) => import("react").ReactElement<any, string | import("react").JSXElementConstructor<any>>;
export default _default;

View File

@ -0,0 +1,43 @@
export default OakComponent({
isList: false,
properties: {
value: '',
getDecidedMenuContent: (menuContent) => undefined,
},
data: {
editor: null,
},
lifetimes: {
detached() {
const { editor } = this.state;
if (editor == null)
return;
editor.destroy();
this.setEditor(null);
},
},
listeners: {
'editor,value'(prev, next) {
if (prev.editor !== next.editor ||
prev.value !== next.value) {
if (next.editor && next.value) {
next.editor.setHtml(next.value);
}
}
},
},
methods: {
setEditor(editor) {
this.setState({
editor,
});
},
async setHtml(html) {
this.setState({
html,
});
if (html && html !== '<p><br></p>') {
}
},
}
});

View File

@ -0,0 +1,3 @@
.container {
width: 100%;
}

View File

@ -0,0 +1,12 @@
import { EntityDict } from "../../../oak-app-domain";
import { WebComponentProps } from 'oak-frontend-base';
import "@wangeditor/editor/dist/css/style.css";
import { IDomEditor } from '@wangeditor/editor';
export default function Render(props: WebComponentProps<EntityDict, keyof EntityDict, false, {
value: string;
editor: IDomEditor;
getDecidedMenuContent: (menuContent: any) => void;
}, {
setEditor: (editor: IDomEditor | null) => void;
setHtml: (html: string) => void;
}>): import("react/jsx-runtime").JSX.Element;

View File

@ -0,0 +1,40 @@
import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
import Style from './web.module.less';
import "@wangeditor/editor/dist/css/style.css"; // 引入 css
import { Editor, Toolbar } from "@wangeditor/editor-for-react";
const toolbarConfig = {
excludeKeys: [
"blockquote",
"fullScreen",
"headerSelect",
"|",
"bold",
"group-more-style",
"bgColor",
"bulletedList",
"numberedList",
"todo",
"group-image",
"group-video",
"insertTable",
"codeBlock",
],
}; // TS 语法
export default function Render(props) {
const { value, editor, getDecidedMenuContent } = props.data;
const { setEditor, setHtml } = props.methods;
return (_jsxs("div", { className: Style.container, children: [_jsx(Toolbar, { editor: editor, defaultConfig: toolbarConfig, mode: "default", style: {
borderBottom: '1px solid #ccc',
} }), _jsx(Editor, { defaultConfig: {
placeholder: '请输入内容...',
}, value: value, onCreated: setEditor, onChange: (editorDom) => {
const html = editorDom.getHtml();
if (html && html !== '<p><br></p>') {
getDecidedMenuContent(html);
}
}, mode: "default", style: {
minHeight: 200,
maxHeight: 400,
overflowY: 'auto',
} })] }));
}

View File

@ -0,0 +1,33 @@
.container {
width: 100%;
background: var(--oak-bg-color-container);
padding: 10px;
.warn {
font-size: 16px;
line-height: 30px;
}
}
.tabs {
background: #F5F5F5;
padding: 10px;
.conditionalMenu {
display: flex;
flex-direction: row;
.tagList {
width: 20%;
margin-right: 20px;
}
.tagHelp {
background: var(--oak-bg-color-container);
padding: 10px;
width: 100%;
border-top-left-radius: 8px;
border-top-right-radius: 8px;
}
}
}

7
es/components/wechatMenu/web.pc.d.ts vendored Normal file
View File

@ -0,0 +1,7 @@
import { WebComponentProps } from 'oak-frontend-base';
import { EntityDict } from '../../oak-app-domain';
export default function Render(props: WebComponentProps<EntityDict, 'wechatMenu', true, {
is_menu_open: boolean;
applicationId: string;
menuId: string;
}, {}>): import("react/jsx-runtime").JSX.Element | null;

View File

@ -0,0 +1,39 @@
import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
import { useState } from 'react';
import WechatMenu from './menu';
import ConditionalMenu from './conditionalMenu';
import Style from './web.module.less';
import { Tabs } from 'antd';
import TagList from './tagList';
export default function Render(props) {
const { menuId, oakFullpath, is_menu_open, applicationId } = props.data;
const {} = props.methods;
const [menuType, setMenuType] = useState('common');
const [tag, setTag] = useState({});
const getTag = (tag) => {
setTag(tag);
};
const items = [
{
key: '1',
label: '通用菜单',
children: _jsx(WechatMenu, { menuId: menuId ? menuId : undefined, oakPath: '$wechatMenu', applicationId: applicationId, oakAutoUnmount: true, menuType: menuType }),
},
{
key: '2',
label: '个性化菜单',
children: _jsxs("div", { className: Style.conditionalMenu, children: [_jsx("div", { className: Style.tagList, children: _jsx(TagList, { oakAutoUnmount: true, oakPath: '$wechatPublicTag', applicationId: applicationId, getTag: getTag }) }), tag.id ? (_jsx(ConditionalMenu, { oakPath: '$conditionalMenu', applicationId: applicationId, oakAutoUnmount: true, tagId: tag.id, menuType: menuType })) : (_jsx("div", { className: Style.tagHelp, children: "\u8BF7\u9009\u62E9\u4E00\u4E2A\u6807\u7B7E" }))] }),
},
];
if (oakFullpath) {
return (_jsx("div", { children: is_menu_open ? (_jsx("div", { className: Style.tabs, children: _jsx(Tabs, { defaultActiveKey: '1', items: items, onChange: (key) => {
if (key === '1') {
setMenuType('common');
}
else {
setMenuType('conditional');
}
} }) })) : (_jsx("div", { className: Style.container, children: _jsx("div", { className: Style.warn, children: "\u5C1A\u672A\u5F00\u542F\u83DC\u5355\uFF0C\u8BF7\u5148\u524D\u5F80\u5FAE\u4FE1\u516C\u4F17\u5E73\u53F0\u5F00\u542F\u3002" }) })) }));
}
return null;
}

18
es/entities/WechatMenu.d.ts vendored Normal file
View File

@ -0,0 +1,18 @@
import { Int } from 'oak-domain/lib/types/DataType';
import { EntityShape } from 'oak-domain/lib/types/Entity';
import { Schema as Application } from './Application';
import { Schema as WechatPublicTag } from './WechatPublicTag';
type Config = {
button: any[];
matchrule?: {
tag_id?: string;
};
};
export interface Schema extends EntityShape {
menuId?: Int<4>;
menuConfig: Config;
application: Application;
publishState: 'wait' | 'success' | 'fail';
wechatPublicTag?: WechatPublicTag;
}
export {};

23
es/entities/WechatMenu.js Normal file
View File

@ -0,0 +1,23 @@
;
const entityDesc = {
locales: {
zh_CN: {
name: '微信菜单',
attr: {
menuId: '菜单Id',
menuConfig: '菜单配置',
application: '应用',
publishState: '发布状态',
wechatPublicTag: '标签',
},
v: {
publishState: {
wait: '等待发布',
success: '发布成功',
fail: '发布失败',
}
}
},
},
};
export {};

View File

@ -5,6 +5,7 @@ import { ExtraFile2 } from './extraFile2';
import { Application } from './application';
import { Config } from './config';
import { WeiXinJsSdk } from './weiXinJsSdk';
import { WechatMenu } from './wechatMenu';
import { BasicFeatures } from 'oak-frontend-base';
import AspectDict from '../aspects/AspectDict';
import { AppType } from '../oak-app-domain/Application/Schema';
@ -21,4 +22,5 @@ export type GeneralFeatures<ED extends EntityDict, Cxt extends BackendRuntimeCon
config: Config<ED, Cxt, FrontCxt, AD>;
weiXinJsSdk: WeiXinJsSdk<ED, Cxt, FrontCxt, AD>;
theme: Theme<ED, Cxt, FrontCxt, AD>;
wechatMenu: WechatMenu<ED, Cxt, FrontCxt, AD>;
};

View File

@ -4,10 +4,12 @@ import { ExtraFile2 } from './extraFile2';
import { Application } from './application';
import { Config } from './config';
import { WeiXinJsSdk } from './weiXinJsSdk';
import { WechatMenu } from './wechatMenu';
import Theme from './theme';
export function initialize(basicFeatures, type, domain) {
const application = new Application(type, domain, basicFeatures.cache, basicFeatures.localStorage);
const token = new Token(basicFeatures.cache, basicFeatures.localStorage, basicFeatures.environment);
const wechatMenu = new WechatMenu(basicFeatures.cache, basicFeatures.localStorage);
// 临时代码,合并后再删
const extraFile = new ExtraFile(basicFeatures.cache, application, basicFeatures.locales);
const extraFile2 = new ExtraFile2(basicFeatures.cache, application, basicFeatures.locales);
@ -22,5 +24,6 @@ export function initialize(basicFeatures, type, domain) {
config,
weiXinJsSdk,
theme,
wechatMenu
};
}

58
es/features/wechatMenu.d.ts vendored Normal file
View File

@ -0,0 +1,58 @@
import { Feature } from 'oak-frontend-base';
import { CommonAspectDict } from 'oak-common-aspect';
import { EntityDict } from '../oak-app-domain';
import AspectDict from '../aspects/AspectDict';
import { BackendRuntimeContext } from '../context/BackendRuntimeContext';
import { FrontendRuntimeContext } from '../context/FrontendRuntimeContext';
import { Cache } from 'oak-frontend-base/es/features/cache';
import { LocalStorage } from 'oak-frontend-base/es/features/localStorage';
export declare class WechatMenu<ED extends EntityDict, Cxt extends BackendRuntimeContext<ED>, FrontCxt extends FrontendRuntimeContext<ED, Cxt, AD>, AD extends AspectDict<ED, Cxt> & CommonAspectDict<ED, Cxt>> extends Feature {
private cache;
private storage;
constructor(cache: Cache<ED, Cxt, FrontCxt, AD>, storage: LocalStorage);
getCurrentMenu(params: {
applicationId: string;
}): Promise<ReturnType<(AD & CommonAspectDict<ED, Cxt>)["getCurrentMenu"]>>;
getMenu(params: {
applicationId: string;
}): Promise<ReturnType<(AD & CommonAspectDict<ED, Cxt>)["getMenu"]>>;
createMenu(params: {
applicationId: string;
menuConfig: any;
}): Promise<ReturnType<(AD & CommonAspectDict<ED, Cxt>)["createMenu"]>>;
createConditionalMenu(params: {
applicationId: string;
menuConfig: any;
}): Promise<ReturnType<(AD & CommonAspectDict<ED, Cxt>)["createConditionalMenu"]>>;
deleteConditionalMenu(params: {
applicationId: string;
menuid: number;
}): Promise<ReturnType<(AD & CommonAspectDict<ED, Cxt>)["deleteConditionalMenu"]>>;
batchGetArticle(params: {
applicationId: string;
offset?: number;
count: number;
noContent?: 0 | 1;
}): Promise<ReturnType<(AD & CommonAspectDict<ED, Cxt>)["batchGetArticle"]>>;
getArticle(params: {
applicationId: string;
article_id: string;
}): Promise<ReturnType<(AD & CommonAspectDict<ED, Cxt>)["getArticle"]>>;
createMaterial(params: {
applicationId: string;
type: 'image' | 'voice' | 'video' | 'thumb';
media: FormData;
description?: FormData;
}): Promise<ReturnType<(AD & CommonAspectDict<ED, Cxt>)["createMaterial"]>>;
batchGetMaterialList(params: {
applicationId: string;
type: 'image' | 'video' | 'voice' | 'news';
offset?: number;
count: number;
}): Promise<ReturnType<(AD & CommonAspectDict<ED, Cxt>)["batchGetMaterialList"]>>;
getMaterial(params: {
applicationId: string;
type: 'image' | 'video' | 'voice' | 'news';
media_id: string;
}): Promise<ReturnType<(AD & CommonAspectDict<ED, Cxt>)["getMaterial"]>>;
}

50
es/features/wechatMenu.js Normal file
View File

@ -0,0 +1,50 @@
import { Feature } from 'oak-frontend-base';
export class WechatMenu extends Feature {
cache;
storage;
constructor(cache, storage) {
super();
this.cache = cache;
this.storage = storage;
}
async getCurrentMenu(params) {
const callBack = await this.cache.exec('getCurrentMenu', params);
return callBack.result;
}
async getMenu(params) {
const callBack = await this.cache.exec('getMenu', params);
return callBack.result;
}
async createMenu(params) {
const callBack = await this.cache.exec('createMenu', params);
return callBack.result;
}
async createConditionalMenu(params) {
const callBack = await this.cache.exec('createConditionalMenu', params);
return callBack.result;
}
async deleteConditionalMenu(params) {
const callBack = await this.cache.exec('deleteConditionalMenu', params);
return callBack.result;
}
async batchGetArticle(params) {
const callBack = await this.cache.exec('batchGetArticle', params);
return callBack.result;
}
async getArticle(params) {
const callBack = await this.cache.exec('getArticle', params);
return callBack.result;
}
async createMaterial(params) {
const callBack = await this.cache.exec('createMaterial', params);
return callBack.result;
}
async batchGetMaterialList(params) {
const callBack = await this.cache.exec('batchGetMaterialList', params);
return callBack.result;
}
async getMaterial(params) {
const callBack = await this.cache.exec('getMaterial', params);
return callBack.result;
}
}

View File

@ -11,6 +11,7 @@ import * as MessageTypeTemplateId from "../MessageTypeTemplateId/Schema";
import * as Notification from "../Notification/Schema";
import * as SessionMessage from "../SessionMessage/Schema";
import * as Token from "../Token/Schema";
import * as WechatMenu from "../WechatMenu/Schema";
import * as WechatPublicTag from "../WechatPublicTag/Schema";
import * as WechatQrCode from "../WechatQrCode/Schema";
import * as WechatUser from "../WechatUser/Schema";
@ -88,6 +89,8 @@ export type Schema = EntityShape & {
sessionMessage$application$$aggr?: AggregationResult<SessionMessage.Schema>;
token$application?: Array<Token.Schema>;
token$application$$aggr?: AggregationResult<Token.Schema>;
wechatMenu$application?: Array<WechatMenu.Schema>;
wechatMenu$application$$aggr?: AggregationResult<WechatMenu.Schema>;
wechatPublicTag$application?: Array<WechatPublicTag.Schema>;
wechatPublicTag$application$$aggr?: AggregationResult<WechatPublicTag.Schema>;
wechatQrCode$application?: Array<WechatQrCode.Schema>;
@ -115,6 +118,7 @@ type AttrFilter = {
notification$application: Notification.Filter & SubQueryPredicateMetadata;
sessionMessage$application: SessionMessage.Filter & SubQueryPredicateMetadata;
token$application: Token.Filter & SubQueryPredicateMetadata;
wechatMenu$application: WechatMenu.Filter & SubQueryPredicateMetadata;
wechatPublicTag$application: WechatPublicTag.Filter & SubQueryPredicateMetadata;
wechatQrCode$application: WechatQrCode.Filter & SubQueryPredicateMetadata;
wechatUser$application: WechatUser.Filter & SubQueryPredicateMetadata;
@ -159,6 +163,12 @@ export type Projection = {
token$application$$aggr?: Token.Aggregation & {
$entity: "token";
};
wechatMenu$application?: WechatMenu.Selection & {
$entity: "wechatMenu";
};
wechatMenu$application$$aggr?: WechatMenu.Aggregation & {
$entity: "wechatMenu";
};
wechatPublicTag$application?: WechatPublicTag.Selection & {
$entity: "wechatPublicTag";
};
@ -234,6 +244,7 @@ export type CreateOperationData = FormCreateData<Omit<OpSchema, "systemId">> & (
notification$application?: OakOperation<Notification.UpdateOperation["action"], Omit<Notification.UpdateOperationData, "application" | "applicationId">, Omit<Notification.Filter, "application" | "applicationId">> | OakOperation<"create", Omit<Notification.CreateOperationData, "application" | "applicationId">[]> | Array<OakOperation<"create", Omit<Notification.CreateOperationData, "application" | "applicationId">> | OakOperation<Notification.UpdateOperation["action"], Omit<Notification.UpdateOperationData, "application" | "applicationId">, Omit<Notification.Filter, "application" | "applicationId">>>;
sessionMessage$application?: OakOperation<SessionMessage.UpdateOperation["action"], Omit<SessionMessage.UpdateOperationData, "application" | "applicationId">, Omit<SessionMessage.Filter, "application" | "applicationId">> | OakOperation<"create", Omit<SessionMessage.CreateOperationData, "application" | "applicationId">[]> | Array<OakOperation<"create", Omit<SessionMessage.CreateOperationData, "application" | "applicationId">> | OakOperation<SessionMessage.UpdateOperation["action"], Omit<SessionMessage.UpdateOperationData, "application" | "applicationId">, Omit<SessionMessage.Filter, "application" | "applicationId">>>;
token$application?: OakOperation<Token.UpdateOperation["action"], Omit<Token.UpdateOperationData, "application" | "applicationId">, Omit<Token.Filter, "application" | "applicationId">> | OakOperation<"create", Omit<Token.CreateOperationData, "application" | "applicationId">[]> | Array<OakOperation<"create", Omit<Token.CreateOperationData, "application" | "applicationId">> | OakOperation<Token.UpdateOperation["action"], Omit<Token.UpdateOperationData, "application" | "applicationId">, Omit<Token.Filter, "application" | "applicationId">>>;
wechatMenu$application?: OakOperation<WechatMenu.UpdateOperation["action"], Omit<WechatMenu.UpdateOperationData, "application" | "applicationId">, Omit<WechatMenu.Filter, "application" | "applicationId">> | OakOperation<"create", Omit<WechatMenu.CreateOperationData, "application" | "applicationId">[]> | Array<OakOperation<"create", Omit<WechatMenu.CreateOperationData, "application" | "applicationId">> | OakOperation<WechatMenu.UpdateOperation["action"], Omit<WechatMenu.UpdateOperationData, "application" | "applicationId">, Omit<WechatMenu.Filter, "application" | "applicationId">>>;
wechatPublicTag$application?: OakOperation<WechatPublicTag.UpdateOperation["action"], Omit<WechatPublicTag.UpdateOperationData, "application" | "applicationId">, Omit<WechatPublicTag.Filter, "application" | "applicationId">> | OakOperation<"create", Omit<WechatPublicTag.CreateOperationData, "application" | "applicationId">[]> | Array<OakOperation<"create", Omit<WechatPublicTag.CreateOperationData, "application" | "applicationId">> | OakOperation<WechatPublicTag.UpdateOperation["action"], Omit<WechatPublicTag.UpdateOperationData, "application" | "applicationId">, Omit<WechatPublicTag.Filter, "application" | "applicationId">>>;
wechatQrCode$application?: OakOperation<WechatQrCode.UpdateOperation["action"], Omit<WechatQrCode.UpdateOperationData, "application" | "applicationId">, Omit<WechatQrCode.Filter, "application" | "applicationId">> | OakOperation<"create", Omit<WechatQrCode.CreateOperationData, "application" | "applicationId">[]> | Array<OakOperation<"create", Omit<WechatQrCode.CreateOperationData, "application" | "applicationId">> | OakOperation<WechatQrCode.UpdateOperation["action"], Omit<WechatQrCode.UpdateOperationData, "application" | "applicationId">, Omit<WechatQrCode.Filter, "application" | "applicationId">>>;
wechatUser$application?: OakOperation<WechatUser.UpdateOperation["action"], Omit<WechatUser.UpdateOperationData, "application" | "applicationId">, Omit<WechatUser.Filter, "application" | "applicationId">> | OakOperation<"create", Omit<WechatUser.CreateOperationData, "application" | "applicationId">[]> | Array<OakOperation<"create", Omit<WechatUser.CreateOperationData, "application" | "applicationId">> | OakOperation<WechatUser.UpdateOperation["action"], Omit<WechatUser.UpdateOperationData, "application" | "applicationId">, Omit<WechatUser.Filter, "application" | "applicationId">>>;
@ -260,6 +271,7 @@ export type UpdateOperationData = FormUpdateData<Omit<OpSchema, "systemId">> & (
notification$application?: OakOperation<Notification.UpdateOperation["action"], Omit<Notification.UpdateOperationData, "application" | "applicationId">, Omit<Notification.Filter, "application" | "applicationId">> | OakOperation<Notification.RemoveOperation["action"], Omit<Notification.RemoveOperationData, "application" | "applicationId">, Omit<Notification.Filter, "application" | "applicationId">> | OakOperation<"create", Omit<Notification.CreateOperationData, "application" | "applicationId">[]> | Array<OakOperation<"create", Omit<Notification.CreateOperationData, "application" | "applicationId">> | OakOperation<Notification.UpdateOperation["action"], Omit<Notification.UpdateOperationData, "application" | "applicationId">, Omit<Notification.Filter, "application" | "applicationId">> | OakOperation<Notification.RemoveOperation["action"], Omit<Notification.RemoveOperationData, "application" | "applicationId">, Omit<Notification.Filter, "application" | "applicationId">>>;
sessionMessage$application?: OakOperation<SessionMessage.UpdateOperation["action"], Omit<SessionMessage.UpdateOperationData, "application" | "applicationId">, Omit<SessionMessage.Filter, "application" | "applicationId">> | OakOperation<SessionMessage.RemoveOperation["action"], Omit<SessionMessage.RemoveOperationData, "application" | "applicationId">, Omit<SessionMessage.Filter, "application" | "applicationId">> | OakOperation<"create", Omit<SessionMessage.CreateOperationData, "application" | "applicationId">[]> | Array<OakOperation<"create", Omit<SessionMessage.CreateOperationData, "application" | "applicationId">> | OakOperation<SessionMessage.UpdateOperation["action"], Omit<SessionMessage.UpdateOperationData, "application" | "applicationId">, Omit<SessionMessage.Filter, "application" | "applicationId">> | OakOperation<SessionMessage.RemoveOperation["action"], Omit<SessionMessage.RemoveOperationData, "application" | "applicationId">, Omit<SessionMessage.Filter, "application" | "applicationId">>>;
token$application?: OakOperation<Token.UpdateOperation["action"], Omit<Token.UpdateOperationData, "application" | "applicationId">, Omit<Token.Filter, "application" | "applicationId">> | OakOperation<Token.RemoveOperation["action"], Omit<Token.RemoveOperationData, "application" | "applicationId">, Omit<Token.Filter, "application" | "applicationId">> | OakOperation<"create", Omit<Token.CreateOperationData, "application" | "applicationId">[]> | Array<OakOperation<"create", Omit<Token.CreateOperationData, "application" | "applicationId">> | OakOperation<Token.UpdateOperation["action"], Omit<Token.UpdateOperationData, "application" | "applicationId">, Omit<Token.Filter, "application" | "applicationId">> | OakOperation<Token.RemoveOperation["action"], Omit<Token.RemoveOperationData, "application" | "applicationId">, Omit<Token.Filter, "application" | "applicationId">>>;
wechatMenu$application?: OakOperation<WechatMenu.UpdateOperation["action"], Omit<WechatMenu.UpdateOperationData, "application" | "applicationId">, Omit<WechatMenu.Filter, "application" | "applicationId">> | OakOperation<WechatMenu.RemoveOperation["action"], Omit<WechatMenu.RemoveOperationData, "application" | "applicationId">, Omit<WechatMenu.Filter, "application" | "applicationId">> | OakOperation<"create", Omit<WechatMenu.CreateOperationData, "application" | "applicationId">[]> | Array<OakOperation<"create", Omit<WechatMenu.CreateOperationData, "application" | "applicationId">> | OakOperation<WechatMenu.UpdateOperation["action"], Omit<WechatMenu.UpdateOperationData, "application" | "applicationId">, Omit<WechatMenu.Filter, "application" | "applicationId">> | OakOperation<WechatMenu.RemoveOperation["action"], Omit<WechatMenu.RemoveOperationData, "application" | "applicationId">, Omit<WechatMenu.Filter, "application" | "applicationId">>>;
wechatPublicTag$application?: OakOperation<WechatPublicTag.UpdateOperation["action"], Omit<WechatPublicTag.UpdateOperationData, "application" | "applicationId">, Omit<WechatPublicTag.Filter, "application" | "applicationId">> | OakOperation<WechatPublicTag.RemoveOperation["action"], Omit<WechatPublicTag.RemoveOperationData, "application" | "applicationId">, Omit<WechatPublicTag.Filter, "application" | "applicationId">> | OakOperation<"create", Omit<WechatPublicTag.CreateOperationData, "application" | "applicationId">[]> | Array<OakOperation<"create", Omit<WechatPublicTag.CreateOperationData, "application" | "applicationId">> | OakOperation<WechatPublicTag.UpdateOperation["action"], Omit<WechatPublicTag.UpdateOperationData, "application" | "applicationId">, Omit<WechatPublicTag.Filter, "application" | "applicationId">> | OakOperation<WechatPublicTag.RemoveOperation["action"], Omit<WechatPublicTag.RemoveOperationData, "application" | "applicationId">, Omit<WechatPublicTag.Filter, "application" | "applicationId">>>;
wechatQrCode$application?: OakOperation<WechatQrCode.UpdateOperation["action"], Omit<WechatQrCode.UpdateOperationData, "application" | "applicationId">, Omit<WechatQrCode.Filter, "application" | "applicationId">> | OakOperation<WechatQrCode.RemoveOperation["action"], Omit<WechatQrCode.RemoveOperationData, "application" | "applicationId">, Omit<WechatQrCode.Filter, "application" | "applicationId">> | OakOperation<"create", Omit<WechatQrCode.CreateOperationData, "application" | "applicationId">[]> | Array<OakOperation<"create", Omit<WechatQrCode.CreateOperationData, "application" | "applicationId">> | OakOperation<WechatQrCode.UpdateOperation["action"], Omit<WechatQrCode.UpdateOperationData, "application" | "applicationId">, Omit<WechatQrCode.Filter, "application" | "applicationId">> | OakOperation<WechatQrCode.RemoveOperation["action"], Omit<WechatQrCode.RemoveOperationData, "application" | "applicationId">, Omit<WechatQrCode.Filter, "application" | "applicationId">>>;
wechatUser$application?: OakOperation<WechatUser.UpdateOperation["action"], Omit<WechatUser.UpdateOperationData, "application" | "applicationId">, Omit<WechatUser.Filter, "application" | "applicationId">> | OakOperation<WechatUser.RemoveOperation["action"], Omit<WechatUser.RemoveOperationData, "application" | "applicationId">, Omit<WechatUser.Filter, "application" | "applicationId">> | OakOperation<"create", Omit<WechatUser.CreateOperationData, "application" | "applicationId">[]> | Array<OakOperation<"create", Omit<WechatUser.CreateOperationData, "application" | "applicationId">> | OakOperation<WechatUser.UpdateOperation["action"], Omit<WechatUser.UpdateOperationData, "application" | "applicationId">, Omit<WechatUser.Filter, "application" | "applicationId">> | OakOperation<WechatUser.RemoveOperation["action"], Omit<WechatUser.RemoveOperationData, "application" | "applicationId">, Omit<WechatUser.Filter, "application" | "applicationId">>>;

View File

@ -39,6 +39,7 @@ import { EntityDef as Token } from "./Token/Schema";
import { EntityDef as UserSystem } from "./UserSystem/Schema";
import { EntityDef as UserWechatPublicTag } from "./UserWechatPublicTag/Schema";
import { EntityDef as WechatLogin } from "./WechatLogin/Schema";
import { EntityDef as WechatMenu } from "./WechatMenu/Schema";
import { EntityDef as WechatPublicTag } from "./WechatPublicTag/Schema";
import { EntityDef as WechatQrCode } from "./WechatQrCode/Schema";
import { EntityDef as WechatUser } from "./WechatUser/Schema";
@ -84,6 +85,7 @@ export type EntityDict = {
userSystem: UserSystem;
userWechatPublicTag: UserWechatPublicTag;
wechatLogin: WechatLogin;
wechatMenu: WechatMenu;
wechatPublicTag: WechatPublicTag;
wechatQrCode: WechatQrCode;
wechatUser: WechatUser;

View File

@ -11,18 +11,19 @@ import * as UserEntityGrant from "../UserEntityGrant/Schema";
import * as UserSystem from "../UserSystem/Schema";
import * as UserWechatPublicTag from "../UserWechatPublicTag/Schema";
import * as WechatLogin from "../WechatLogin/Schema";
import * as WechatMenu from "../WechatMenu/Schema";
import * as WechatPublicTag from "../WechatPublicTag/Schema";
import * as WechatQrCode from "../WechatQrCode/Schema";
import * as WechatUser from "../WechatUser/Schema";
export type OpSchema = EntityShape & {
modiId: ForeignKey<"modi">;
entity: "user" | "userEntityGrant" | "userSystem" | "userWechatPublicTag" | "wechatLogin" | "wechatPublicTag" | "wechatQrCode" | "wechatUser" | string;
entity: "user" | "userEntityGrant" | "userSystem" | "userWechatPublicTag" | "wechatLogin" | "wechatMenu" | "wechatPublicTag" | "wechatQrCode" | "wechatUser" | string;
entityId: String<64>;
};
export type OpAttr = keyof OpSchema;
export type Schema = EntityShape & {
modiId: ForeignKey<"modi">;
entity: "user" | "userEntityGrant" | "userSystem" | "userWechatPublicTag" | "wechatLogin" | "wechatPublicTag" | "wechatQrCode" | "wechatUser" | string;
entity: "user" | "userEntityGrant" | "userSystem" | "userWechatPublicTag" | "wechatLogin" | "wechatMenu" | "wechatPublicTag" | "wechatQrCode" | "wechatUser" | string;
entityId: String<64>;
modi: Modi.Schema;
user?: User.Schema;
@ -30,6 +31,7 @@ export type Schema = EntityShape & {
userSystem?: UserSystem.Schema;
userWechatPublicTag?: UserWechatPublicTag.Schema;
wechatLogin?: WechatLogin.Schema;
wechatMenu?: WechatMenu.Schema;
wechatPublicTag?: WechatPublicTag.Schema;
wechatQrCode?: WechatQrCode.Schema;
wechatUser?: WechatUser.Schema;
@ -43,13 +45,14 @@ type AttrFilter = {
$$updateAt$$: Q_DateValue;
modiId: Q_StringValue;
modi: Modi.Filter;
entity: Q_EnumValue<"user" | "userEntityGrant" | "userSystem" | "userWechatPublicTag" | "wechatLogin" | "wechatPublicTag" | "wechatQrCode" | "wechatUser" | string>;
entity: Q_EnumValue<"user" | "userEntityGrant" | "userSystem" | "userWechatPublicTag" | "wechatLogin" | "wechatMenu" | "wechatPublicTag" | "wechatQrCode" | "wechatUser" | string>;
entityId: Q_StringValue;
user: User.Filter;
userEntityGrant: UserEntityGrant.Filter;
userSystem: UserSystem.Filter;
userWechatPublicTag: UserWechatPublicTag.Filter;
wechatLogin: WechatLogin.Filter;
wechatMenu: WechatMenu.Filter;
wechatPublicTag: WechatPublicTag.Filter;
wechatQrCode: WechatQrCode.Filter;
wechatUser: WechatUser.Filter;
@ -71,6 +74,7 @@ export type Projection = {
userSystem?: UserSystem.Projection;
userWechatPublicTag?: UserWechatPublicTag.Projection;
wechatLogin?: WechatLogin.Projection;
wechatMenu?: WechatMenu.Projection;
wechatPublicTag?: WechatPublicTag.Projection;
wechatQrCode?: WechatQrCode.Projection;
wechatUser?: WechatUser.Projection;
@ -96,6 +100,9 @@ type UserWechatPublicTagIdProjection = OneOf<{
type WechatLoginIdProjection = OneOf<{
entityId: number;
}>;
type WechatMenuIdProjection = OneOf<{
entityId: number;
}>;
type WechatPublicTagIdProjection = OneOf<{
entityId: number;
}>;
@ -131,6 +138,8 @@ export type SortAttr = {
userWechatPublicTag: UserWechatPublicTag.SortAttr;
} | {
wechatLogin: WechatLogin.SortAttr;
} | {
wechatMenu: WechatMenu.SortAttr;
} | {
wechatPublicTag: WechatPublicTag.SortAttr;
} | {
@ -211,6 +220,17 @@ export type CreateOperationData = FormCreateData<Omit<OpSchema, "entity" | "enti
} | {
entity: "wechatLogin";
entityId: ForeignKey<"WechatLogin">;
} | {
entity?: never;
entityId?: never;
wechatMenu: WechatMenu.CreateSingleOperation;
} | {
entity: "wechatMenu";
entityId: ForeignKey<"WechatMenu">;
wechatMenu: WechatMenu.UpdateOperation;
} | {
entity: "wechatMenu";
entityId: ForeignKey<"WechatMenu">;
} | {
entity?: never;
entityId?: never;
@ -284,6 +304,10 @@ export type UpdateOperationData = FormUpdateData<Omit<OpSchema, "entity" | "enti
wechatLogin?: WechatLogin.CreateSingleOperation | WechatLogin.UpdateOperation | WechatLogin.RemoveOperation;
entityId?: never;
entity?: never;
} | {
wechatMenu?: WechatMenu.CreateSingleOperation | WechatMenu.UpdateOperation | WechatMenu.RemoveOperation;
entityId?: never;
entity?: never;
} | {
wechatPublicTag?: WechatPublicTag.CreateSingleOperation | WechatPublicTag.UpdateOperation | WechatPublicTag.RemoveOperation;
entityId?: never;
@ -297,8 +321,8 @@ export type UpdateOperationData = FormUpdateData<Omit<OpSchema, "entity" | "enti
entityId?: never;
entity?: never;
} | {
entity?: ("user" | "userEntityGrant" | "userSystem" | "userWechatPublicTag" | "wechatLogin" | "wechatPublicTag" | "wechatQrCode" | "wechatUser" | string) | null;
entityId?: ForeignKey<"User" | "UserEntityGrant" | "UserSystem" | "UserWechatPublicTag" | "WechatLogin" | "WechatPublicTag" | "WechatQrCode" | "WechatUser"> | null;
entity?: ("user" | "userEntityGrant" | "userSystem" | "userWechatPublicTag" | "wechatLogin" | "wechatMenu" | "wechatPublicTag" | "wechatQrCode" | "wechatUser" | string) | null;
entityId?: ForeignKey<"User" | "UserEntityGrant" | "UserSystem" | "UserWechatPublicTag" | "WechatLogin" | "WechatMenu" | "WechatPublicTag" | "WechatQrCode" | "WechatUser"> | null;
}) & {
[k: string]: any;
};
@ -315,6 +339,8 @@ export type RemoveOperationData = {} & (({
userWechatPublicTag?: UserWechatPublicTag.UpdateOperation | UserWechatPublicTag.RemoveOperation;
} | {
wechatLogin?: WechatLogin.UpdateOperation | WechatLogin.RemoveOperation;
} | {
wechatMenu?: WechatMenu.UpdateOperation | WechatMenu.RemoveOperation;
} | {
wechatPublicTag?: WechatPublicTag.UpdateOperation | WechatPublicTag.RemoveOperation;
} | {
@ -332,6 +358,7 @@ export type UserEntityGrantIdSubQuery = Selection<UserEntityGrantIdProjection>;
export type UserSystemIdSubQuery = Selection<UserSystemIdProjection>;
export type UserWechatPublicTagIdSubQuery = Selection<UserWechatPublicTagIdProjection>;
export type WechatLoginIdSubQuery = Selection<WechatLoginIdProjection>;
export type WechatMenuIdSubQuery = Selection<WechatMenuIdProjection>;
export type WechatPublicTagIdSubQuery = Selection<WechatPublicTagIdProjection>;
export type WechatQrCodeIdSubQuery = Selection<WechatQrCodeIdProjection>;
export type WechatUserIdSubQuery = Selection<WechatUserIdProjection>;

View File

@ -12,7 +12,7 @@ export const desc = {
params: {
length: 32
},
ref: ["user", "userEntityGrant", "userSystem", "userWechatPublicTag", "wechatLogin", "wechatPublicTag", "wechatQrCode", "wechatUser"]
ref: ["user", "userEntityGrant", "userSystem", "userWechatPublicTag", "wechatLogin", "wechatMenu", "wechatPublicTag", "wechatQrCode", "wechatUser"]
},
entityId: {
notNull: true,

View File

@ -11,18 +11,19 @@ import * as UserEntityGrant from "../UserEntityGrant/Schema";
import * as UserSystem from "../UserSystem/Schema";
import * as UserWechatPublicTag from "../UserWechatPublicTag/Schema";
import * as WechatLogin from "../WechatLogin/Schema";
import * as WechatMenu from "../WechatMenu/Schema";
import * as WechatPublicTag from "../WechatPublicTag/Schema";
import * as WechatQrCode from "../WechatQrCode/Schema";
import * as WechatUser from "../WechatUser/Schema";
export type OpSchema = EntityShape & {
operId: ForeignKey<"oper">;
entity: "user" | "userEntityGrant" | "userSystem" | "userWechatPublicTag" | "wechatLogin" | "wechatPublicTag" | "wechatQrCode" | "wechatUser" | string;
entity: "user" | "userEntityGrant" | "userSystem" | "userWechatPublicTag" | "wechatLogin" | "wechatMenu" | "wechatPublicTag" | "wechatQrCode" | "wechatUser" | string;
entityId: String<64>;
};
export type OpAttr = keyof OpSchema;
export type Schema = EntityShape & {
operId: ForeignKey<"oper">;
entity: "user" | "userEntityGrant" | "userSystem" | "userWechatPublicTag" | "wechatLogin" | "wechatPublicTag" | "wechatQrCode" | "wechatUser" | string;
entity: "user" | "userEntityGrant" | "userSystem" | "userWechatPublicTag" | "wechatLogin" | "wechatMenu" | "wechatPublicTag" | "wechatQrCode" | "wechatUser" | string;
entityId: String<64>;
oper: Oper.Schema;
user?: User.Schema;
@ -30,6 +31,7 @@ export type Schema = EntityShape & {
userSystem?: UserSystem.Schema;
userWechatPublicTag?: UserWechatPublicTag.Schema;
wechatLogin?: WechatLogin.Schema;
wechatMenu?: WechatMenu.Schema;
wechatPublicTag?: WechatPublicTag.Schema;
wechatQrCode?: WechatQrCode.Schema;
wechatUser?: WechatUser.Schema;
@ -43,13 +45,14 @@ type AttrFilter = {
$$updateAt$$: Q_DateValue;
operId: Q_StringValue;
oper: Oper.Filter;
entity: Q_EnumValue<"user" | "userEntityGrant" | "userSystem" | "userWechatPublicTag" | "wechatLogin" | "wechatPublicTag" | "wechatQrCode" | "wechatUser" | string>;
entity: Q_EnumValue<"user" | "userEntityGrant" | "userSystem" | "userWechatPublicTag" | "wechatLogin" | "wechatMenu" | "wechatPublicTag" | "wechatQrCode" | "wechatUser" | string>;
entityId: Q_StringValue;
user: User.Filter;
userEntityGrant: UserEntityGrant.Filter;
userSystem: UserSystem.Filter;
userWechatPublicTag: UserWechatPublicTag.Filter;
wechatLogin: WechatLogin.Filter;
wechatMenu: WechatMenu.Filter;
wechatPublicTag: WechatPublicTag.Filter;
wechatQrCode: WechatQrCode.Filter;
wechatUser: WechatUser.Filter;
@ -71,6 +74,7 @@ export type Projection = {
userSystem?: UserSystem.Projection;
userWechatPublicTag?: UserWechatPublicTag.Projection;
wechatLogin?: WechatLogin.Projection;
wechatMenu?: WechatMenu.Projection;
wechatPublicTag?: WechatPublicTag.Projection;
wechatQrCode?: WechatQrCode.Projection;
wechatUser?: WechatUser.Projection;
@ -96,6 +100,9 @@ type UserWechatPublicTagIdProjection = OneOf<{
type WechatLoginIdProjection = OneOf<{
entityId: number;
}>;
type WechatMenuIdProjection = OneOf<{
entityId: number;
}>;
type WechatPublicTagIdProjection = OneOf<{
entityId: number;
}>;
@ -131,6 +138,8 @@ export type SortAttr = {
userWechatPublicTag: UserWechatPublicTag.SortAttr;
} | {
wechatLogin: WechatLogin.SortAttr;
} | {
wechatMenu: WechatMenu.SortAttr;
} | {
wechatPublicTag: WechatPublicTag.SortAttr;
} | {
@ -208,6 +217,17 @@ export type CreateOperationData = FormCreateData<Omit<OpSchema, "entity" | "enti
} | {
entity: "wechatLogin";
entityId: ForeignKey<"WechatLogin">;
} | {
entity?: never;
entityId?: never;
wechatMenu: WechatMenu.CreateSingleOperation;
} | {
entity: "wechatMenu";
entityId: ForeignKey<"WechatMenu">;
wechatMenu: WechatMenu.UpdateOperation;
} | {
entity: "wechatMenu";
entityId: ForeignKey<"WechatMenu">;
} | {
entity?: never;
entityId?: never;
@ -275,6 +295,10 @@ export type UpdateOperationData = FormUpdateData<Omit<OpSchema, "entity" | "enti
wechatLogin?: WechatLogin.CreateSingleOperation | WechatLogin.UpdateOperation | WechatLogin.RemoveOperation;
entityId?: never;
entity?: never;
} | {
wechatMenu?: WechatMenu.CreateSingleOperation | WechatMenu.UpdateOperation | WechatMenu.RemoveOperation;
entityId?: never;
entity?: never;
} | {
wechatPublicTag?: WechatPublicTag.CreateSingleOperation | WechatPublicTag.UpdateOperation | WechatPublicTag.RemoveOperation;
entityId?: never;
@ -288,8 +312,8 @@ export type UpdateOperationData = FormUpdateData<Omit<OpSchema, "entity" | "enti
entityId?: never;
entity?: never;
} | {
entity?: ("user" | "userEntityGrant" | "userSystem" | "userWechatPublicTag" | "wechatLogin" | "wechatPublicTag" | "wechatQrCode" | "wechatUser" | string) | null;
entityId?: ForeignKey<"User" | "UserEntityGrant" | "UserSystem" | "UserWechatPublicTag" | "WechatLogin" | "WechatPublicTag" | "WechatQrCode" | "WechatUser"> | null;
entity?: ("user" | "userEntityGrant" | "userSystem" | "userWechatPublicTag" | "wechatLogin" | "wechatMenu" | "wechatPublicTag" | "wechatQrCode" | "wechatUser" | string) | null;
entityId?: ForeignKey<"User" | "UserEntityGrant" | "UserSystem" | "UserWechatPublicTag" | "WechatLogin" | "WechatMenu" | "WechatPublicTag" | "WechatQrCode" | "WechatUser"> | null;
}) & {
[k: string]: any;
};
@ -304,6 +328,8 @@ export type RemoveOperationData = {} & ({
userWechatPublicTag?: UserWechatPublicTag.UpdateOperation | UserWechatPublicTag.RemoveOperation;
} | {
wechatLogin?: WechatLogin.UpdateOperation | WechatLogin.RemoveOperation;
} | {
wechatMenu?: WechatMenu.UpdateOperation | WechatMenu.RemoveOperation;
} | {
wechatPublicTag?: WechatPublicTag.UpdateOperation | WechatPublicTag.RemoveOperation;
} | {
@ -321,6 +347,7 @@ export type UserEntityGrantIdSubQuery = Selection<UserEntityGrantIdProjection>;
export type UserSystemIdSubQuery = Selection<UserSystemIdProjection>;
export type UserWechatPublicTagIdSubQuery = Selection<UserWechatPublicTagIdProjection>;
export type WechatLoginIdSubQuery = Selection<WechatLoginIdProjection>;
export type WechatMenuIdSubQuery = Selection<WechatMenuIdProjection>;
export type WechatPublicTagIdSubQuery = Selection<WechatPublicTagIdProjection>;
export type WechatQrCodeIdSubQuery = Selection<WechatQrCodeIdProjection>;
export type WechatUserIdSubQuery = Selection<WechatUserIdProjection>;

View File

@ -12,7 +12,7 @@ export const desc = {
params: {
length: 32
},
ref: ["user", "userEntityGrant", "userSystem", "userWechatPublicTag", "wechatLogin", "wechatPublicTag", "wechatQrCode", "wechatUser"]
ref: ["user", "userEntityGrant", "userSystem", "userWechatPublicTag", "wechatLogin", "wechatMenu", "wechatPublicTag", "wechatQrCode", "wechatUser"]
},
entityId: {
notNull: true,

View File

@ -39,6 +39,7 @@ import { desc as tokenDesc } from "./Token/Storage";
import { desc as userSystemDesc } from "./UserSystem/Storage";
import { desc as userWechatPublicTagDesc } from "./UserWechatPublicTag/Storage";
import { desc as wechatLoginDesc } from "./WechatLogin/Storage";
import { desc as wechatMenuDesc } from "./WechatMenu/Storage";
import { desc as wechatPublicTagDesc } from "./WechatPublicTag/Storage";
import { desc as wechatQrCodeDesc } from "./WechatQrCode/Storage";
import { desc as wechatUserDesc } from "./WechatUser/Storage";
@ -84,6 +85,7 @@ export const storageSchema = {
userSystem: userSystemDesc,
userWechatPublicTag: userWechatPublicTagDesc,
wechatLogin: wechatLoginDesc,
wechatMenu: wechatMenuDesc,
wechatPublicTag: wechatPublicTagDesc,
wechatQrCode: wechatQrCodeDesc,
wechatUser: wechatUserDesc

202
es/oak-app-domain/WechatMenu/Schema.d.ts vendored Normal file
View File

@ -0,0 +1,202 @@
import { ForeignKey, JsonProjection } from "oak-domain/lib/types/DataType";
import { Q_DateValue, Q_NumberValue, Q_StringValue, Q_EnumValue, NodeId, MakeFilter, ExprOp, ExpressionKey, JsonFilter, SubQueryPredicateMetadata } from "oak-domain/lib/types/Demand";
import { OneOf } from "oak-domain/lib/types/Polyfill";
import { FormCreateData, FormUpdateData, DeduceAggregation, Operation as OakOperation, Selection as OakSelection, MakeAction as OakMakeAction, AggregationResult } from "oak-domain/lib/types/Entity";
import { GenericAction } from "oak-domain/lib/actions/action";
import { Int } from "oak-domain/lib/types/DataType";
import { EntityShape } from "oak-domain/lib/types/Entity";
import * as Application from "../Application/Schema";
import * as WechatPublicTag from "../WechatPublicTag/Schema";
import * as ModiEntity from "../ModiEntity/Schema";
import * as OperEntity from "../OperEntity/Schema";
type Config = {
button: any[];
matchrule?: {
tag_id?: string;
};
};
export type OpSchema = EntityShape & {
menuId?: Int<4> | null;
menuConfig: Config;
applicationId: ForeignKey<"application">;
publishState: 'wait' | 'success' | 'fail';
wechatPublicTagId?: ForeignKey<"wechatPublicTag"> | null;
};
export type OpAttr = keyof OpSchema;
export type Schema = EntityShape & {
menuId?: Int<4> | null;
menuConfig: Config;
applicationId: ForeignKey<"application">;
publishState: 'wait' | 'success' | 'fail';
wechatPublicTagId?: ForeignKey<"wechatPublicTag"> | null;
application: Application.Schema;
wechatPublicTag?: WechatPublicTag.Schema | null;
modiEntity$entity?: Array<ModiEntity.Schema>;
modiEntity$entity$$aggr?: AggregationResult<ModiEntity.Schema>;
operEntity$entity?: Array<OperEntity.Schema>;
operEntity$entity$$aggr?: AggregationResult<OperEntity.Schema>;
} & {
[A in ExpressionKey]?: any;
};
type AttrFilter = {
id: Q_StringValue;
$$createAt$$: Q_DateValue;
$$seq$$: Q_StringValue;
$$updateAt$$: Q_DateValue;
menuId: Q_NumberValue;
menuConfig: JsonFilter<Config>;
applicationId: Q_StringValue;
application: Application.Filter;
publishState: Q_EnumValue<'wait' | 'success' | 'fail'>;
wechatPublicTagId: Q_StringValue;
wechatPublicTag: WechatPublicTag.Filter;
modiEntity$entity: ModiEntity.Filter & SubQueryPredicateMetadata;
operEntity$entity: OperEntity.Filter & SubQueryPredicateMetadata;
};
export type Filter = MakeFilter<AttrFilter & ExprOp<OpAttr | string>>;
export type Projection = {
"#id"?: NodeId;
[k: string]: any;
id?: number;
$$createAt$$?: number;
$$updateAt$$?: number;
$$seq$$?: number;
menuId?: number;
menuConfig?: number | JsonProjection<Config>;
applicationId?: number;
application?: Application.Projection;
publishState?: number;
wechatPublicTagId?: number;
wechatPublicTag?: WechatPublicTag.Projection;
modiEntity$entity?: ModiEntity.Selection & {
$entity: "modiEntity";
};
modiEntity$entity$$aggr?: ModiEntity.Aggregation & {
$entity: "modiEntity";
};
operEntity$entity?: OperEntity.Selection & {
$entity: "operEntity";
};
operEntity$entity$$aggr?: OperEntity.Aggregation & {
$entity: "operEntity";
};
} & Partial<ExprOp<OpAttr | string>>;
type WechatMenuIdProjection = OneOf<{
id: number;
}>;
type ApplicationIdProjection = OneOf<{
applicationId: number;
}>;
type WechatPublicTagIdProjection = OneOf<{
wechatPublicTagId: number;
}>;
export type SortAttr = {
id: number;
} | {
$$createAt$$: number;
} | {
$$seq$$: number;
} | {
$$updateAt$$: number;
} | {
menuId: number;
} | {
menuConfig: number;
} | {
applicationId: number;
} | {
application: Application.SortAttr;
} | {
publishState: number;
} | {
wechatPublicTagId: number;
} | {
wechatPublicTag: WechatPublicTag.SortAttr;
} | {
[k: string]: any;
} | OneOf<ExprOp<OpAttr | string>>;
export type SortNode = {
$attr: SortAttr;
$direction?: "asc" | "desc";
};
export type Sorter = SortNode[];
export type SelectOperation<P extends Object = Projection> = OakSelection<"select", P, Filter, Sorter>;
export type Selection<P extends Object = Projection> = SelectOperation<P>;
export type Aggregation = DeduceAggregation<Projection, Filter, Sorter>;
export type CreateOperationData = FormCreateData<Omit<OpSchema, "applicationId" | "wechatPublicTagId">> & (({
applicationId?: never;
application: Application.CreateSingleOperation;
} | {
applicationId: ForeignKey<"application">;
application?: Application.UpdateOperation;
} | {
applicationId: ForeignKey<"application">;
}) & ({
wechatPublicTagId?: never;
wechatPublicTag?: WechatPublicTag.CreateSingleOperation;
} | {
wechatPublicTagId: ForeignKey<"wechatPublicTag">;
wechatPublicTag?: WechatPublicTag.UpdateOperation;
} | {
wechatPublicTagId?: ForeignKey<"wechatPublicTag">;
})) & {
modiEntity$entity?: OakOperation<"create", Omit<ModiEntity.CreateOperationData, "entity" | "entityId">[]> | Array<OakOperation<"create", Omit<ModiEntity.CreateOperationData, "entity" | "entityId">>>;
operEntity$entity?: OakOperation<"create", Omit<OperEntity.CreateOperationData, "entity" | "entityId">[]> | Array<OakOperation<"create", Omit<OperEntity.CreateOperationData, "entity" | "entityId">>>;
};
export type CreateSingleOperation = OakOperation<"create", CreateOperationData>;
export type CreateMultipleOperation = OakOperation<"create", Array<CreateOperationData>>;
export type CreateOperation = CreateSingleOperation | CreateMultipleOperation;
export type UpdateOperationData = FormUpdateData<Omit<OpSchema, "applicationId" | "wechatPublicTagId">> & (({
application: Application.CreateSingleOperation;
applicationId?: never;
} | {
application: Application.UpdateOperation;
applicationId?: never;
} | {
application: Application.RemoveOperation;
applicationId?: never;
} | {
application?: never;
applicationId?: ForeignKey<"application"> | null;
}) & ({
wechatPublicTag: WechatPublicTag.CreateSingleOperation;
wechatPublicTagId?: never;
} | {
wechatPublicTag: WechatPublicTag.UpdateOperation;
wechatPublicTagId?: never;
} | {
wechatPublicTag: WechatPublicTag.RemoveOperation;
wechatPublicTagId?: never;
} | {
wechatPublicTag?: never;
wechatPublicTagId?: ForeignKey<"wechatPublicTag"> | null;
})) & {
[k: string]: any;
modiEntity$entity?: OakOperation<"create", Omit<ModiEntity.CreateOperationData, "entity" | "entityId">[]> | Array<OakOperation<"create", Omit<ModiEntity.CreateOperationData, "entity" | "entityId">>>;
operEntity$entity?: OakOperation<"create", Omit<OperEntity.CreateOperationData, "entity" | "entityId">[]> | Array<OakOperation<"create", Omit<OperEntity.CreateOperationData, "entity" | "entityId">>>;
};
export type UpdateOperation = OakOperation<"update" | string, UpdateOperationData, Filter, Sorter>;
export type RemoveOperationData = {} & (({
application?: Application.UpdateOperation | Application.RemoveOperation;
}) & ({
wechatPublicTag?: WechatPublicTag.UpdateOperation | WechatPublicTag.RemoveOperation;
}));
export type RemoveOperation = OakOperation<"remove", RemoveOperationData, Filter, Sorter>;
export type Operation = CreateOperation | UpdateOperation | RemoveOperation;
export type ApplicationIdSubQuery = Selection<ApplicationIdProjection>;
export type WechatPublicTagIdSubQuery = Selection<WechatPublicTagIdProjection>;
export type WechatMenuIdSubQuery = Selection<WechatMenuIdProjection>;
export type EntityDef = {
Schema: Schema;
OpSchema: OpSchema;
Action: OakMakeAction<GenericAction> | string;
Selection: Selection;
Aggregation: Aggregation;
Operation: Operation;
Create: CreateOperation;
Update: UpdateOperation;
Remove: RemoveOperation;
CreateSingle: CreateSingleOperation;
CreateMulti: CreateMultipleOperation;
};
export {};

View File

@ -0,0 +1 @@
export {};

View File

@ -0,0 +1,3 @@
import { StorageDesc } from "oak-domain/lib/types/Storage";
import { OpSchema } from "./Schema";
export declare const desc: StorageDesc<OpSchema>;

View File

@ -0,0 +1,32 @@
import { genericActions as actions } from "oak-domain/lib/actions/action";
export const desc = {
attributes: {
menuId: {
type: "int",
params: {
width: 4,
signed: true
}
},
menuConfig: {
notNull: true,
type: "object"
},
applicationId: {
notNull: true,
type: "ref",
ref: "application"
},
publishState: {
notNull: true,
type: "enum",
enumeration: ["wait", "success", "fail"]
},
wechatPublicTagId: {
type: "ref",
ref: "wechatPublicTag"
}
},
actionType: "crud",
actions
};

View File

@ -0,0 +1 @@
{ "name": "微信菜单", "attr": { "menuId": "菜单Id", "menuConfig": "菜单配置", "application": "应用", "publishState": "发布状态", "wechatPublicTag": "标签" }, "v": { "publishState": { "wait": "等待发布", "success": "发布成功", "fail": "发布失败" } } }

View File

@ -7,6 +7,7 @@ import { String, Datetime, Boolean, Uint } from "oak-domain/lib/types/DataType";
import { EntityShape } from "oak-domain/lib/types/Entity";
import * as Application from "../Application/Schema";
import * as UserWechatPublicTag from "../UserWechatPublicTag/Schema";
import * as WechatMenu from "../WechatMenu/Schema";
import * as ModiEntity from "../ModiEntity/Schema";
import * as OperEntity from "../OperEntity/Schema";
export type OpSchema = EntityShape & {
@ -26,6 +27,8 @@ export type Schema = EntityShape & {
application: Application.Schema;
userWechatPublicTag$wechatPublicTag?: Array<UserWechatPublicTag.Schema>;
userWechatPublicTag$wechatPublicTag$$aggr?: AggregationResult<UserWechatPublicTag.Schema>;
wechatMenu$wechatPublicTag?: Array<WechatMenu.Schema>;
wechatMenu$wechatPublicTag$$aggr?: AggregationResult<WechatMenu.Schema>;
modiEntity$entity?: Array<ModiEntity.Schema>;
modiEntity$entity$$aggr?: AggregationResult<ModiEntity.Schema>;
operEntity$entity?: Array<OperEntity.Schema>;
@ -45,6 +48,7 @@ type AttrFilter = {
sync: Q_BooleanValue;
syncAt: Q_DateValue;
userWechatPublicTag$wechatPublicTag: UserWechatPublicTag.Filter & SubQueryPredicateMetadata;
wechatMenu$wechatPublicTag: WechatMenu.Filter & SubQueryPredicateMetadata;
modiEntity$entity: ModiEntity.Filter & SubQueryPredicateMetadata;
operEntity$entity: OperEntity.Filter & SubQueryPredicateMetadata;
};
@ -68,6 +72,12 @@ export type Projection = {
userWechatPublicTag$wechatPublicTag$$aggr?: UserWechatPublicTag.Aggregation & {
$entity: "userWechatPublicTag";
};
wechatMenu$wechatPublicTag?: WechatMenu.Selection & {
$entity: "wechatMenu";
};
wechatMenu$wechatPublicTag$$aggr?: WechatMenu.Aggregation & {
$entity: "wechatMenu";
};
modiEntity$entity?: ModiEntity.Selection & {
$entity: "modiEntity";
};
@ -128,6 +138,7 @@ export type CreateOperationData = FormCreateData<Omit<OpSchema, "applicationId">
applicationId: ForeignKey<"application">;
})) & {
userWechatPublicTag$wechatPublicTag?: OakOperation<UserWechatPublicTag.UpdateOperation["action"], Omit<UserWechatPublicTag.UpdateOperationData, "wechatPublicTag" | "wechatPublicTagId">, Omit<UserWechatPublicTag.Filter, "wechatPublicTag" | "wechatPublicTagId">> | OakOperation<"create", Omit<UserWechatPublicTag.CreateOperationData, "wechatPublicTag" | "wechatPublicTagId">[]> | Array<OakOperation<"create", Omit<UserWechatPublicTag.CreateOperationData, "wechatPublicTag" | "wechatPublicTagId">> | OakOperation<UserWechatPublicTag.UpdateOperation["action"], Omit<UserWechatPublicTag.UpdateOperationData, "wechatPublicTag" | "wechatPublicTagId">, Omit<UserWechatPublicTag.Filter, "wechatPublicTag" | "wechatPublicTagId">>>;
wechatMenu$wechatPublicTag?: OakOperation<WechatMenu.UpdateOperation["action"], Omit<WechatMenu.UpdateOperationData, "wechatPublicTag" | "wechatPublicTagId">, Omit<WechatMenu.Filter, "wechatPublicTag" | "wechatPublicTagId">> | OakOperation<"create", Omit<WechatMenu.CreateOperationData, "wechatPublicTag" | "wechatPublicTagId">[]> | Array<OakOperation<"create", Omit<WechatMenu.CreateOperationData, "wechatPublicTag" | "wechatPublicTagId">> | OakOperation<WechatMenu.UpdateOperation["action"], Omit<WechatMenu.UpdateOperationData, "wechatPublicTag" | "wechatPublicTagId">, Omit<WechatMenu.Filter, "wechatPublicTag" | "wechatPublicTagId">>>;
modiEntity$entity?: OakOperation<"create", Omit<ModiEntity.CreateOperationData, "entity" | "entityId">[]> | Array<OakOperation<"create", Omit<ModiEntity.CreateOperationData, "entity" | "entityId">>>;
operEntity$entity?: OakOperation<"create", Omit<OperEntity.CreateOperationData, "entity" | "entityId">[]> | Array<OakOperation<"create", Omit<OperEntity.CreateOperationData, "entity" | "entityId">>>;
};
@ -149,6 +160,7 @@ export type UpdateOperationData = FormUpdateData<Omit<OpSchema, "applicationId">
})) & {
[k: string]: any;
userWechatPublicTag$wechatPublicTag?: OakOperation<UserWechatPublicTag.UpdateOperation["action"], Omit<UserWechatPublicTag.UpdateOperationData, "wechatPublicTag" | "wechatPublicTagId">, Omit<UserWechatPublicTag.Filter, "wechatPublicTag" | "wechatPublicTagId">> | OakOperation<UserWechatPublicTag.RemoveOperation["action"], Omit<UserWechatPublicTag.RemoveOperationData, "wechatPublicTag" | "wechatPublicTagId">, Omit<UserWechatPublicTag.Filter, "wechatPublicTag" | "wechatPublicTagId">> | OakOperation<"create", Omit<UserWechatPublicTag.CreateOperationData, "wechatPublicTag" | "wechatPublicTagId">[]> | Array<OakOperation<"create", Omit<UserWechatPublicTag.CreateOperationData, "wechatPublicTag" | "wechatPublicTagId">> | OakOperation<UserWechatPublicTag.UpdateOperation["action"], Omit<UserWechatPublicTag.UpdateOperationData, "wechatPublicTag" | "wechatPublicTagId">, Omit<UserWechatPublicTag.Filter, "wechatPublicTag" | "wechatPublicTagId">> | OakOperation<UserWechatPublicTag.RemoveOperation["action"], Omit<UserWechatPublicTag.RemoveOperationData, "wechatPublicTag" | "wechatPublicTagId">, Omit<UserWechatPublicTag.Filter, "wechatPublicTag" | "wechatPublicTagId">>>;
wechatMenu$wechatPublicTag?: OakOperation<WechatMenu.UpdateOperation["action"], Omit<WechatMenu.UpdateOperationData, "wechatPublicTag" | "wechatPublicTagId">, Omit<WechatMenu.Filter, "wechatPublicTag" | "wechatPublicTagId">> | OakOperation<WechatMenu.RemoveOperation["action"], Omit<WechatMenu.RemoveOperationData, "wechatPublicTag" | "wechatPublicTagId">, Omit<WechatMenu.Filter, "wechatPublicTag" | "wechatPublicTagId">> | OakOperation<"create", Omit<WechatMenu.CreateOperationData, "wechatPublicTag" | "wechatPublicTagId">[]> | Array<OakOperation<"create", Omit<WechatMenu.CreateOperationData, "wechatPublicTag" | "wechatPublicTagId">> | OakOperation<WechatMenu.UpdateOperation["action"], Omit<WechatMenu.UpdateOperationData, "wechatPublicTag" | "wechatPublicTagId">, Omit<WechatMenu.Filter, "wechatPublicTag" | "wechatPublicTagId">> | OakOperation<WechatMenu.RemoveOperation["action"], Omit<WechatMenu.RemoveOperationData, "wechatPublicTag" | "wechatPublicTagId">, Omit<WechatMenu.Filter, "wechatPublicTag" | "wechatPublicTagId">>>;
modiEntity$entity?: OakOperation<"create", Omit<ModiEntity.CreateOperationData, "entity" | "entityId">[]> | Array<OakOperation<"create", Omit<ModiEntity.CreateOperationData, "entity" | "entityId">>>;
operEntity$entity?: OakOperation<"create", Omit<OperEntity.CreateOperationData, "entity" | "entityId">[]> | Array<OakOperation<"create", Omit<OperEntity.CreateOperationData, "entity" | "entityId">>>;
};

View File

@ -39,6 +39,7 @@ import * as Token from "./Token/Schema";
import * as UserSystem from "./UserSystem/Schema";
import * as UserWechatPublicTag from "./UserWechatPublicTag/Schema";
import * as WechatLogin from "./WechatLogin/Schema";
import * as WechatMenu from "./WechatMenu/Schema";
import * as WechatPublicTag from "./WechatPublicTag/Schema";
import * as WechatQrCode from "./WechatQrCode/Schema";
import * as WechatUser from "./WechatUser/Schema";
@ -167,6 +168,8 @@ export type ApplicationIdSubQuery = {
entity: "sessionMessage";
}) | (Token.ApplicationIdSubQuery & {
entity: "token";
}) | (WechatMenu.ApplicationIdSubQuery & {
entity: "wechatMenu";
}) | (WechatPublicTag.ApplicationIdSubQuery & {
entity: "wechatPublicTag";
}) | (WechatQrCode.ApplicationIdSubQuery & {
@ -385,9 +388,20 @@ export type WechatLoginIdSubQuery = {
entity: "wechatLogin";
}) | any;
};
export type WechatMenuIdSubQuery = {
[K in "$in" | "$nin"]?: (ModiEntity.WechatMenuIdSubQuery & {
entity: "modiEntity";
}) | (OperEntity.WechatMenuIdSubQuery & {
entity: "operEntity";
}) | (WechatMenu.WechatMenuIdSubQuery & {
entity: "wechatMenu";
}) | any;
};
export type WechatPublicTagIdSubQuery = {
[K in "$in" | "$nin"]?: (UserWechatPublicTag.WechatPublicTagIdSubQuery & {
entity: "userWechatPublicTag";
}) | (WechatMenu.WechatPublicTagIdSubQuery & {
entity: "wechatMenu";
}) | (ModiEntity.WechatPublicTagIdSubQuery & {
entity: "modiEntity";
}) | (OperEntity.WechatPublicTagIdSubQuery & {

View File

@ -3,6 +3,7 @@ import { Tabs, Card, Descriptions, Typography, Button } from 'antd';
import PageHeader from '../../../components/common/pageHeader';
import Style from './web.module.less';
import MessageTypeTemplateIdList from '../../../components/messageTypeTemplateId/list';
import WechatMenu from '../../../components/wechatMenu';
export default function Render(props) {
const { oakId, tabValue, config, name, description, type, system } = props.data;
const { t, navigateBack, onTabClick, goWechatPublicTagList } = props.methods;
@ -25,5 +26,12 @@ export default function Render(props) {
children: (_jsx(MessageTypeTemplateIdList, { oakAutoUnmount: true, applicationId: oakId, oakPath: `$application-detail-mttId-${oakId}` })),
});
}
if (['wechatPublic'].includes(type)) {
items.push({
label: '菜单管理',
key: 'menu',
children: (_jsx(WechatMenu, { oakAutoUnmount: true, applicationId: oakId, oakPath: `$application-detail-menu-${oakId}` }))
});
}
return (_jsx(PageHeader, { showBack: true, title: "\u5E94\u7528\u6982\u89C8", children: _jsx("div", { className: Style.container, children: _jsx(Card, { title: name, bordered: false, extra: Actions, children: _jsx(Tabs, { items: items }) }) }) }));
}

View File

@ -105,5 +105,50 @@ export type GeneralAspectDict<ED extends EntityDict, Cxt extends BackendRuntimeC
result: string;
times?: number;
}>;
getCurrentMenu: (params: {
applicationId: string;
}, context: Cxt) => Promise<any>;
getMenu: (params: {
applicationId: string;
}, context: Cxt) => Promise<any>;
createMenu: (params: {
applicationId: string;
menuConfig: any;
}, context: Cxt) => Promise<any>;
createConditionalMenu: (params: {
applicationId: string;
menuConfig: any;
}, context: Cxt) => Promise<any>;
deleteConditionalMenu: (params: {
applicationId: string;
menuid: number;
}, context: Cxt) => Promise<any>;
batchGetArticle: (params: {
applicationId: string;
offset?: number;
count: number;
noContent?: 0 | 1;
}, context: Cxt) => Promise<any>;
getArticle: (params: {
applicationId: string;
article_id: string;
}, context: Cxt) => Promise<any>;
createMaterial: (params: {
applicationId: string;
type: 'image' | 'voice' | 'video' | 'thumb';
media: FormData;
description?: FormData;
}, context: Cxt) => Promise<any>;
batchGetMaterialList: (params: {
applicationId: string;
type: 'image' | 'video' | 'voice' | 'news';
offset?: number;
count: number;
}, context: Cxt) => Promise<any>;
getMaterial: (params: {
applicationId: string;
type: 'image' | 'video' | 'voice' | 'news';
media_id: string;
}, context: Cxt) => Promise<any>;
};
export default GeneralAspectDict;

View File

@ -7,6 +7,7 @@ import { createWechatLogin } from './wechatLogin';
import { unbindingWechat } from './wechatUser';
import { getMpUnlimitWxaCode } from './wechatQrCode';
import { confirmUserEntityGrant } from './userEntityGrant';
import { getCurrentMenu, getMenu, createMenu, createConditionalMenu, deleteConditionalMenu, batchGetArticle, getArticle, createMaterial, batchGetMaterialList, getMaterial } from './wechatMenu';
declare const aspectDict: {
mergeUser: typeof mergeUser;
switchTo: typeof switchTo;
@ -31,5 +32,15 @@ declare const aspectDict: {
updateUserPassword: typeof updateUserPassword;
getMpUnlimitWxaCode: typeof getMpUnlimitWxaCode;
confirmUserEntityGrant: typeof confirmUserEntityGrant;
getCurrentMenu: typeof getCurrentMenu;
getMenu: typeof getMenu;
createMenu: typeof createMenu;
createConditionalMenu: typeof createConditionalMenu;
deleteConditionalMenu: typeof deleteConditionalMenu;
batchGetArticle: typeof batchGetArticle;
getArticle: typeof getArticle;
createMaterial: typeof createMaterial;
batchGetMaterialList: typeof batchGetMaterialList;
getMaterial: typeof getMaterial;
};
export default aspectDict;

View File

@ -9,6 +9,7 @@ const wechatLogin_1 = require("./wechatLogin");
const wechatUser_1 = require("./wechatUser");
const wechatQrCode_1 = require("./wechatQrCode");
const userEntityGrant_1 = require("./userEntityGrant");
const wechatMenu_1 = require("./wechatMenu");
const aspectDict = {
mergeUser: user_1.mergeUser,
switchTo: token_1.switchTo,
@ -33,5 +34,15 @@ const aspectDict = {
updateUserPassword: user_1.updateUserPassword,
getMpUnlimitWxaCode: wechatQrCode_1.getMpUnlimitWxaCode,
confirmUserEntityGrant: userEntityGrant_1.confirmUserEntityGrant,
getCurrentMenu: wechatMenu_1.getCurrentMenu,
getMenu: wechatMenu_1.getMenu,
createMenu: wechatMenu_1.createMenu,
createConditionalMenu: wechatMenu_1.createConditionalMenu,
deleteConditionalMenu: wechatMenu_1.deleteConditionalMenu,
batchGetArticle: wechatMenu_1.batchGetArticle,
getArticle: wechatMenu_1.getArticle,
createMaterial: wechatMenu_1.createMaterial,
batchGetMaterialList: wechatMenu_1.batchGetMaterialList,
getMaterial: wechatMenu_1.getMaterial,
};
exports.default = aspectDict;

47
lib/aspects/wechatMenu.d.ts vendored Normal file
View File

@ -0,0 +1,47 @@
import { EntityDict } from '../oak-app-domain';
import { BackendRuntimeContext } from '../context/BackendRuntimeContext';
export declare function getCurrentMenu<ED extends EntityDict, Cxt extends BackendRuntimeContext<ED>>(params: {
applicationId: string;
}, context: Cxt): Promise<any>;
export declare function getMenu<ED extends EntityDict, Cxt extends BackendRuntimeContext<ED>>(params: {
applicationId: string;
}, context: Cxt): Promise<any>;
export declare function createMenu<ED extends EntityDict, Cxt extends BackendRuntimeContext<ED>>(params: {
applicationId: string;
menuConfig: any;
}, context: Cxt): Promise<any>;
export declare function createConditionalMenu<ED extends EntityDict, Cxt extends BackendRuntimeContext<ED>>(params: {
applicationId: string;
menuConfig: any;
}, context: Cxt): Promise<any>;
export declare function deleteConditionalMenu<ED extends EntityDict, Cxt extends BackendRuntimeContext<ED>>(params: {
applicationId: string;
menuid: number;
}, context: Cxt): Promise<any>;
export declare function batchGetArticle<ED extends EntityDict, Cxt extends BackendRuntimeContext<ED>>(params: {
applicationId: string;
offset?: number;
count: number;
noContent?: 0 | 1;
}, context: Cxt): Promise<any>;
export declare function getArticle<ED extends EntityDict, Cxt extends BackendRuntimeContext<ED>>(params: {
applicationId: string;
article_id: string;
}, context: Cxt): Promise<any>;
export declare function createMaterial<ED extends EntityDict, Cxt extends BackendRuntimeContext<ED>>(params: {
applicationId: string;
type: 'image' | 'voice' | 'video' | 'thumb';
media: FormData;
description?: FormData;
}, context: Cxt): Promise<any>;
export declare function batchGetMaterialList<ED extends EntityDict, Cxt extends BackendRuntimeContext<ED>>(params: {
applicationId: string;
type: 'image' | 'video' | 'voice' | 'news';
offset?: number;
count: number;
}, context: Cxt): Promise<any>;
export declare function getMaterial<ED extends EntityDict, Cxt extends BackendRuntimeContext<ED>>(params: {
applicationId: string;
type: 'image' | 'video' | 'voice' | 'news';
media_id: string;
}, context: Cxt): Promise<any>;

160
lib/aspects/wechatMenu.js Normal file
View File

@ -0,0 +1,160 @@
"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
exports.getMaterial = exports.batchGetMaterialList = exports.createMaterial = exports.getArticle = exports.batchGetArticle = exports.deleteConditionalMenu = exports.createConditionalMenu = exports.createMenu = exports.getMenu = exports.getCurrentMenu = void 0;
const oak_external_sdk_1 = require("oak-external-sdk");
async function getWechatPublicConfig(applicationId, context) {
const [application] = await context.select('application', {
data: {
id: 1,
config: 1,
type: 1,
},
filter: {
id: applicationId,
type: 'wechatPublic'
},
}, {
dontCollect: true
});
return application;
}
async function getCurrentMenu(params, context) {
const application = await getWechatPublicConfig(params.applicationId, context);
if (application) {
const { type, config, systemId } = application;
let appId, appSecret;
const config2 = config;
appId = config2.appId;
appSecret = config2.appSecret;
const wechatInstance = oak_external_sdk_1.WechatSDK.getInstance(appId, type, appSecret);
const result = await wechatInstance.getCurrentMenu();
return result;
}
}
exports.getCurrentMenu = getCurrentMenu;
async function getMenu(params, context) {
const application = await getWechatPublicConfig(params.applicationId, context);
if (application) {
const { type, config, systemId } = application;
let appId, appSecret;
const config2 = config;
appId = config2.appId;
appSecret = config2.appSecret;
const wechatInstance = oak_external_sdk_1.WechatSDK.getInstance(appId, type, appSecret);
const result = await wechatInstance.getMenu();
return result;
}
}
exports.getMenu = getMenu;
async function createMenu(params, context) {
const application = await getWechatPublicConfig(params.applicationId, context);
if (application) {
const { type, config, systemId } = application;
let appId, appSecret;
const config2 = config;
appId = config2.appId;
appSecret = config2.appSecret;
const wechatInstance = oak_external_sdk_1.WechatSDK.getInstance(appId, type, appSecret);
const result = await wechatInstance.createMenu(params.menuConfig);
return result;
}
}
exports.createMenu = createMenu;
async function createConditionalMenu(params, context) {
const application = await getWechatPublicConfig(params.applicationId, context);
if (application) {
const { type, config, systemId } = application;
let appId, appSecret;
const config2 = config;
appId = config2.appId;
appSecret = config2.appSecret;
const wechatInstance = oak_external_sdk_1.WechatSDK.getInstance(appId, type, appSecret);
const result = await wechatInstance.createConditionalMenu(params.menuConfig);
return result;
}
}
exports.createConditionalMenu = createConditionalMenu;
async function deleteConditionalMenu(params, context) {
const application = await getWechatPublicConfig(params.applicationId, context);
if (application) {
const { type, config, systemId } = application;
let appId, appSecret;
const config2 = config;
appId = config2.appId;
appSecret = config2.appSecret;
const wechatInstance = oak_external_sdk_1.WechatSDK.getInstance(appId, type, appSecret);
const result = await wechatInstance.deleteConditionalMenu(params.menuid);
return result;
}
}
exports.deleteConditionalMenu = deleteConditionalMenu;
async function batchGetArticle(params, context) {
const application = await getWechatPublicConfig(params.applicationId, context);
if (application) {
const { type, config, systemId } = application;
let appId, appSecret;
const config2 = config;
appId = config2.appId;
appSecret = config2.appSecret;
const wechatInstance = oak_external_sdk_1.WechatSDK.getInstance(appId, type, appSecret);
const result = await wechatInstance.batchGetArticle(params);
return result;
}
}
exports.batchGetArticle = batchGetArticle;
async function getArticle(params, context) {
const application = await getWechatPublicConfig(params.applicationId, context);
if (application) {
const { type, config, systemId } = application;
let appId, appSecret;
const config2 = config;
appId = config2.appId;
appSecret = config2.appSecret;
const wechatInstance = oak_external_sdk_1.WechatSDK.getInstance(appId, type, appSecret);
const result = await wechatInstance.getArticle(params);
return result;
}
}
exports.getArticle = getArticle;
async function createMaterial(params, context) {
const application = await getWechatPublicConfig(params.applicationId, context);
if (application) {
const { type, config, systemId } = application;
let appId, appSecret;
const config2 = config;
appId = config2.appId;
appSecret = config2.appSecret;
const wechatInstance = oak_external_sdk_1.WechatSDK.getInstance(appId, type, appSecret);
const result = await wechatInstance.createMaterial(params);
return result;
}
}
exports.createMaterial = createMaterial;
async function batchGetMaterialList(params, context) {
const application = await getWechatPublicConfig(params.applicationId, context);
if (application) {
const { type, config, systemId } = application;
let appId, appSecret;
const config2 = config;
appId = config2.appId;
appSecret = config2.appSecret;
const wechatInstance = oak_external_sdk_1.WechatSDK.getInstance(appId, type, appSecret);
const result = await wechatInstance.batchGetMaterialList(params);
return result;
}
}
exports.batchGetMaterialList = batchGetMaterialList;
async function getMaterial(params, context) {
const application = await getWechatPublicConfig(params.applicationId, context);
if (application) {
const { type, config, systemId } = application;
let appId, appSecret;
const config2 = config;
appId = config2.appId;
appSecret = config2.appSecret;
const wechatInstance = oak_external_sdk_1.WechatSDK.getInstance(appId, type, appSecret);
const result = await wechatInstance.getMaterial(params);
return result;
}
}
exports.getMaterial = getMaterial;

View File

@ -0,0 +1,7 @@
/// <reference types="react" />
declare const _default: (props: import("oak-frontend-base").ReactComponentProps<import("../../oak-app-domain").EntityDict, keyof import("../../oak-app-domain").EntityDict, false, {
type: "image" | "video" | "news" | "voice";
getMenuContent: (menuContent: any) => void;
applicationId: string;
}>) => import("react").ReactElement<any, string | import("react").JSXElementConstructor<any>>;
export default _default;

View File

@ -0,0 +1,111 @@
"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
exports.default = OakComponent({
isList: false,
properties: {
type: '',
getMenuContent: (menuContent) => undefined,
applicationId: '',
},
lifetimes: {
async ready() {
const { type, applicationId } = this.props;
let result;
if (type === 'news') {
result = await this.features.wechatMenu.batchGetArticle({ applicationId: applicationId, offset: 0, count: 10, noContent: 0 });
const modifiedResult = await Promise.all(result.item.map(async (ele) => {
const news_item = await Promise.all(ele.content.news_item.map(async (ele2) => {
const coverUrl = await this.getMaterialImg(ele2.thumb_media_id);
return {
...ele2,
coverUrl
};
}));
return {
...ele,
content: {
...ele.content,
news_item
}
};
}));
this.setState({
materials: modifiedResult,
total: result.total_count,
});
}
else {
result = await this.features.wechatMenu.batchGetMaterialList({ applicationId: applicationId, type: type, offset: 0, count: 10 });
this.setState({
materials: result.item,
total: result.total_count,
});
}
}
},
methods: {
async getMaterialList(page) {
const { applicationId } = this.props;
const { type } = this.props;
const offset = (page - 1) * 10;
const result = await this.features.wechatMenu.batchGetMaterialList({ applicationId: applicationId, type: type, offset, count: 10 });
this.setState({
materials: result.item,
total: result.total_count,
});
},
async getArticleList(page) {
const { applicationId } = this.props;
const offset = (page - 1) * 10;
const result = await this.features.wechatMenu.batchGetArticle({ applicationId: applicationId, offset, count: 10, noContent: 0 });
const modifiedResult = await Promise.all(result.item.map(async (ele) => {
const news_item = await Promise.all(ele.content.news_item.map(async (ele2) => {
const coverUrl = await this.getMaterialImg(ele2.thumb_media_id);
return {
...ele2,
coverUrl
};
}));
return {
...ele,
content: {
...ele.content,
news_item
}
};
}));
this.setState({
materials: modifiedResult,
total: result.total_count,
});
},
async upload(media, description) {
const { applicationId } = this.props;
const { type } = this.props;
console.log(media);
const result = await this.features.wechatMenu.createMaterial({ applicationId: applicationId, type: type, media, description });
if (result && result.media_id) {
this.setMessage({
type: 'success',
content: '上传成功',
});
this.getMaterialList(1);
return true;
}
else {
return false;
}
},
async getMaterialImg(media_id) {
const { applicationId } = this.props;
const imgFile = await this.features.wechatMenu.getMaterial({ applicationId: applicationId, type: 'image', media_id });
return new Promise((resolve) => {
const reader = new FileReader();
reader.readAsDataURL(imgFile);
reader.onload = function (e) {
resolve(e.target?.result);
};
});
}
}
});

View File

@ -0,0 +1,22 @@
.container {
display: flex;
flex-direction: column;
width: 100%;
.title {
font-size: 16px;
}
.upload {
display: flex;
flex-direction: row;
justify-content: flex-end;
align-items: center;
margin: 20px 0 0 0;
.help {
color: #B1B2B3;
margin-right: 10px;
}
}
.list {
margin-top: 20px;
}
}

View File

@ -0,0 +1,12 @@
import { EntityDict } from "../../oak-app-domain";
import { WebComponentProps } from 'oak-frontend-base';
export default function Render(props: WebComponentProps<EntityDict, keyof EntityDict, true, {
type: string;
materials: any[];
total: number;
getMenuContent: (menuContent: any) => void;
}, {
getMaterialList: (page: number) => void;
getArticleList: (page: number) => void;
upload: (media: FormData, description?: FormData) => boolean;
}>): import("react/jsx-runtime").JSX.Element;

View File

@ -0,0 +1,250 @@
"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
const tslib_1 = require("tslib");
const jsx_runtime_1 = require("react/jsx-runtime");
const react_1 = require("react");
const antd_1 = require("antd");
const { TextArea } = antd_1.Input;
const icons_1 = require("@ant-design/icons");
const web_module_less_1 = tslib_1.__importDefault(require("./web.module.less"));
const dayjs_1 = tslib_1.__importDefault(require("dayjs"));
const showNews_1 = tslib_1.__importDefault(require("../wechatMenu/showNews"));
function Render(props) {
const { type, materials, total, getMenuContent } = props.data;
const { getMaterialList, setMessage, upload, getArticleList } = props.methods;
const [currentPage, setCurrentPage] = (0, react_1.useState)(1);
const [upsertOpen, setUpsertOpen] = (0, react_1.useState)(false);
const [title, setTitle] = (0, react_1.useState)('');
const [introduction, setIntroduction] = (0, react_1.useState)('');
const [fileList, setFileList] = (0, react_1.useState)([]);
const [video, setVideo] = (0, react_1.useState)(new FormData);
const checkFileType = (filename) => {
const fileExtension = filename?.split('.')?.pop()?.toLowerCase();
let allowedExtensions = [];
if (type === 'image') {
allowedExtensions = ['bmp', 'png', 'jpeg', 'jpg', 'gif'];
}
else if (type === 'voice') {
allowedExtensions = ['mp3', 'wma', 'wav', 'amr'];
}
else {
allowedExtensions = ['mp4'];
}
if (allowedExtensions.includes(fileExtension)) {
return true;
}
else {
setMessage({
content: '文件类型错误',
type: 'error'
});
return false;
}
};
const uploadFile = async (file) => {
if (checkFileType(file.name)) {
const formData = new FormData();
formData.append('media', file);
console.log(file);
upload(formData);
}
else {
return;
}
};
const fileChange = (info) => {
setFileList(info.fileList);
};
const uploadVideo = async (file) => {
if (checkFileType(file.name)) {
const formData = new FormData();
formData.append('media', file);
setVideo(formData);
const updataFileList = fileList.map((ele) => {
return {
...ele,
status: 'done'
};
});
fileChange({ fileList: updataFileList });
}
else {
const updataFileList = fileList.map((ele) => {
return {
...ele,
status: 'error'
};
});
fileChange({ fileList: updataFileList });
}
};
(0, react_1.useEffect)(() => {
if (!open) {
setTitle('');
setIntroduction('');
setFileList([]);
}
}, [open]);
const columns = [
{
dataIndex: 'serial-number',
title: '序号',
render: (value, record, index) => {
return index + 1;
},
width: 100
},
{
dataIndex: 'name',
title: '名称',
},
{
dataIndex: 'update_time',
title: '更新时间',
render: (value, record, index) => {
return (0, jsx_runtime_1.jsx)(jsx_runtime_1.Fragment, { children: (0, dayjs_1.default)(value).format('YYYY-MM-DD HH:mm') });
}
},
];
const newsColumns = [
{
dataIndex: 'serial-number',
title: '序号',
render: (value, record, index) => {
return index + 1;
},
width: 100
},
{
dataIndex: 'coverImg',
title: '封面图',
render: (value, record, index) => {
return ((0, jsx_runtime_1.jsx)("div", { children: record.content.news_item.map((ele) => ((0, jsx_runtime_1.jsx)("div", { children: (0, jsx_runtime_1.jsx)("img", { style: { width: 100 }, src: ele.coverUrl }) }))) }));
}
},
{
dataIndex: 'title',
title: '图文消息标题',
render: (value, record, index) => {
return ((0, jsx_runtime_1.jsx)("div", { children: record.content.news_item.map((ele) => ((0, jsx_runtime_1.jsx)("div", { children: ele.title }))) }));
}
},
{
// dataIndex: 'author',
title: '作者',
render: (value, record, index) => {
return ((0, jsx_runtime_1.jsx)("div", { children: record.content.news_item.map((ele) => ((0, jsx_runtime_1.jsx)("div", { children: ele.author }))) }));
}
},
{
dataIndex: 'digest',
title: '图文信息摘要',
render: (value, record, index) => {
return ((0, jsx_runtime_1.jsx)("div", { children: record.content.news_item.map((ele) => ((0, jsx_runtime_1.jsx)("div", { children: ele.digest }))) }));
}
},
{
dataIndex: 'update_time',
title: '更新时间',
render: (value, record, index) => {
return (0, jsx_runtime_1.jsx)(jsx_runtime_1.Fragment, { children: (0, dayjs_1.default)(value).format('YYYY-MM-DD HH:mm') });
}
},
{
dataIndex: 'op',
title: '操作',
render: (value, record, index) => {
return (0, jsx_runtime_1.jsx)(antd_1.Popover, { content: (0, jsx_runtime_1.jsx)("div", { style: { padding: 12 }, children: (0, jsx_runtime_1.jsx)(showNews_1.default, { oakAutoUnmount: true, news: record.content.news_item }) }), children: (0, jsx_runtime_1.jsx)("div", { style: { cursor: 'pointer', color: '#1677ff' }, children: "\u9884\u89C8" }) });
}
}
];
if (type === 'image') {
columns.splice(1, 0, {
dataIndex: 'url',
title: '图片',
render: (value, record, index) => {
return (0, jsx_runtime_1.jsx)("img", { style: { width: 120, height: 70 }, src: value });
},
});
}
else if (type === 'voice') {
columns.splice(1, 0, {
dataIndex: 'url',
title: '音频',
render: (value, record, index) => {
return (0, jsx_runtime_1.jsxs)("a", { href: value, download: true, style: { color: '#1677FF', cursor: 'pointer' }, children: [(0, jsx_runtime_1.jsx)(icons_1.DownloadOutlined, {}), record.media_id] });
},
});
}
else if (type === 'video') {
columns.splice(1, 0, {
dataIndex: 'url',
title: '视频',
render: (value, record, index) => {
return (0, jsx_runtime_1.jsxs)("a", { href: value, download: true, style: { color: '#1677FF', cursor: 'pointer' }, children: [(0, jsx_runtime_1.jsx)(icons_1.DownloadOutlined, {}), record.media_id] });
},
});
}
else {
}
return ((0, jsx_runtime_1.jsxs)("div", { className: web_module_less_1.default.container, children: [(0, jsx_runtime_1.jsx)("div", { className: web_module_less_1.default.title, children: type === 'news' ? '选择图文' : type === 'image' ? '选择图片' : type === 'voice' ? '插入音频' : '选择视频' }), type !== 'news' && (0, jsx_runtime_1.jsxs)("div", { className: web_module_less_1.default.upload, children: [(0, jsx_runtime_1.jsx)("div", { className: web_module_less_1.default.help, children: type === 'image' ? '大小不超过10M' : type === 'voice' ? '由于版本兼容的原因,你暂时只可以选择60秒内的音频发送' : null }), type === 'video' ? ((0, jsx_runtime_1.jsx)(antd_1.Button, { onClick: () => {
setUpsertOpen(true);
}, children: "\u4E0A\u4F20\u89C6\u9891" })) : ((0, jsx_runtime_1.jsx)(antd_1.Upload, { maxCount: 1, showUploadList: false, customRequest: ({ file }) => {
uploadFile(file);
}, children: (0, jsx_runtime_1.jsxs)(antd_1.Button, { children: ["\u4E0A\u4F20", type === 'image' ? '图片' : '音频'] }) })), (0, jsx_runtime_1.jsx)(antd_1.Modal, { open: upsertOpen, onCancel: () => setUpsertOpen(false), title: '上传视频', footer: (0, jsx_runtime_1.jsxs)(antd_1.Space, { children: [(0, jsx_runtime_1.jsx)(antd_1.Button, { type: 'primary', onClick: () => {
if (title.length === 0) {
setMessage({
type: 'warning',
content: '标题不能为空'
});
return;
}
if (introduction.length === 0) {
setMessage({
type: 'warning',
content: '视频介绍不能为空'
});
return;
}
if (fileList.length === 0 || fileList[0].status === 'error') {
setMessage({
type: 'warning',
content: '请上传视频文件'
});
return;
}
const formData = new FormData;
const descriptionData = {
title,
introduction,
};
formData.append('description', JSON.stringify(descriptionData));
if (upload(video, formData)) {
setUpsertOpen(false);
}
}, children: "\u4E0A\u4F20" }), (0, jsx_runtime_1.jsx)(antd_1.Button, { onClick: () => setUpsertOpen(false), children: "\u53D6\u6D88" })] }), children: (0, jsx_runtime_1.jsxs)("div", { children: [(0, jsx_runtime_1.jsx)(antd_1.Form.Item, { label: (0, jsx_runtime_1.jsx)("div", { className: web_module_less_1.default.label, children: "\u6807\u9898" }), required: true, labelAlign: 'right', labelCol: { span: 4 }, children: (0, jsx_runtime_1.jsx)(antd_1.Input, { showCount: true, maxLength: 20, value: title, onChange: (val) => setTitle(val.target.value) }) }), (0, jsx_runtime_1.jsx)(antd_1.Form.Item, { label: (0, jsx_runtime_1.jsx)("div", { className: web_module_less_1.default.label, children: "\u89C6\u9891\u4ECB\u7ECD" }), required: true, children: (0, jsx_runtime_1.jsx)(TextArea, { showCount: true, maxLength: 300, value: introduction, autoSize: { minRows: 5 }, onChange: (val) => setIntroduction(val.target.value) }) }), (0, jsx_runtime_1.jsx)(antd_1.Form.Item, { label: (0, jsx_runtime_1.jsx)("div", { className: web_module_less_1.default.label, children: "\u4E0A\u4F20\u89C6\u9891" }), required: true, children: (0, jsx_runtime_1.jsx)(antd_1.Upload, { customRequest: ({ file }) => uploadVideo(file), maxCount: 1, onChange: fileChange, fileList: fileList, children: (0, jsx_runtime_1.jsxs)(antd_1.Button, { children: [(0, jsx_runtime_1.jsx)(icons_1.DownloadOutlined, {}), fileList.length > 0 ? '重新' : '', "\u4E0A\u4F20"] }) }) })] }) })] }), (0, jsx_runtime_1.jsx)("div", { className: web_module_less_1.default.list, children: (0, jsx_runtime_1.jsx)(antd_1.Table, { rowKey: type === 'news' ? 'article_id' : 'media_id', dataSource: materials, columns: type === 'news' ? newsColumns : columns, pagination: {
total: total,
pageSize: 10,
current: currentPage,
onChange: (page, pageSize) => {
setCurrentPage(page);
if (type === 'news') {
getArticleList(page);
}
else {
getMaterialList(page);
}
},
}, rowSelection: {
type: 'radio',
onSelect: (record) => {
if (type === 'news') {
getMenuContent(record);
}
else {
getMenuContent(record);
}
},
} }) })] }));
}
exports.default = Render;

View File

@ -0,0 +1,15 @@
/// <reference types="react" />
declare const _default: (props: import("oak-frontend-base").ReactComponentProps<import("../../../oak-app-domain").EntityDict, keyof import("../../../oak-app-domain").EntityDict, false, {
id: string;
config: any;
menuIndex: number;
changeConfig: (config: any) => void;
menuType: string;
getSelectedBtn: (selectedBtn: number) => void;
getSelectedSubBtn: (selectedSubBtn: number) => void;
getCurrentIndex: (currentIndex: number) => void;
errorIndex: number[];
isPreview: boolean;
open: boolean;
}>) => import("react").ReactElement<any, string | import("react").JSXElementConstructor<any>>;
export default _default;

View File

@ -0,0 +1,83 @@
"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
exports.default = OakComponent({
isList: false,
properties: {
id: '',
config: null,
menuIndex: 0,
changeConfig: (config) => undefined,
menuType: '',
getSelectedBtn: (selectedBtn) => undefined,
getSelectedSubBtn: (selectedSubBtn) => undefined,
getCurrentIndex: (currentIndex) => undefined,
errorIndex: [],
isPreview: false,
open: false,
},
data: {},
methods: {
deleteMenuItem(index) {
const { config, changeConfig, menuIndex, menuType } = this.props;
config.button.splice(index, 1);
changeConfig(config);
this.setMessage({
content: '操作成功',
type: 'success'
});
},
toRight(index) {
const { config, changeConfig, menuIndex, menuType } = this.props;
config.button = [
...config.button.slice(0, index - 1),
config.button[index],
config.button[index - 1],
...config.button.slice(index + 1)
];
changeConfig(config);
},
toLeft(index) {
const { config, changeConfig, menuIndex, menuType } = this.props;
config.button = [
...config.button.slice(0, index - 2),
config.button[index - 1],
config.button[index - 2],
...config.button.slice(index)
];
changeConfig(config);
},
toUp(currentIndex, index) {
const { config, changeConfig, menuIndex, menuType } = this.props;
let menu = config.button[currentIndex];
const subMenu = [
...menu.sub_button.slice(0, index - 2),
menu.sub_button[index - 1],
menu.sub_button[index - 2],
...menu.sub_button.slice(index)
];
config.button[currentIndex].sub_button = subMenu;
changeConfig(config);
},
toDown(currentIndex, index) {
const { config, changeConfig, menuIndex, menuType } = this.props;
let menu = config.button[currentIndex];
const subMenu = [
...menu.sub_button.slice(0, index - 1),
menu.sub_button[index],
menu.sub_button[index - 1],
...menu.sub_button.slice(index + 1)
];
config.button[currentIndex].sub_button = subMenu;
changeConfig(config);
},
deleteSubMenuItem(index, currentIndex) {
const { config, changeConfig, menuIndex, menuType } = this.props;
config.button[currentIndex].sub_button.splice(index, 1);
changeConfig(config);
this.setMessage({
content: '操作成功',
type: 'success'
});
},
}
});

View File

@ -0,0 +1,180 @@
.container {
width: 100%;
.phone {
display: flex;
flex-direction: column;
width: 100%;
background: #fcfcfc;
border-radius: 8px;
.topBar {
display: flex;
flex-direction: row;
justify-content: space-between;
height: 30px;
margin: 8px 16px 10px 16px;
align-items: center;
.time {
font-size: 12px;
font-weight: bold;
}
.icons {
display: flex;
flex-direction: row;
}
}
.actionBar {
display: flex;
flex-direction: row;
justify-content: space-between;
margin: 0 10px;
}
.page {
height: 412px;
}
.bottomBar {
height: 68px;
display: flex;
flex-direction: row;
background: #fcfcfc;
border-bottom-left-radius: 8px;
border-bottom-right-radius: 8px;
border-top: 1px solid #EDEEEF;
.keyBoard {
width: 60px;
}
.menu {
flex: 1;
display: flex;
flex-direction: row;
cursor: pointer;
.buttonGroup {
top: 73px;
position: absolute;
justify-content: center;
align-items: center;
display: flex;
height: 48px;
min-width: 48px;
border-radius: 24px;
background: #fcfcfc;
font-size: 24px;
padding: 5px;
box-shadow: 0 1px 6px #e4e8eb;
.buttonItem {
height: 38px;
width: 38px;
border-radius: 50%;
justify-content: center;
align-items: center;
display: flex;
}
.buttonItem:hover {
background: #EDEEEF;
}
}
.menuItem {
flex: 1;
display: flex;
flex-direction: column;
justify-content: center;
align-items: center;
height: 68px;
width: 80px;
position: relative;
.menuName {
width: 100%;
height: 33px;
border-left: 1px solid #EDEEEF;
display: flex;
justify-content: center;
align-items: center;
}
}
.button2 {
margin: 17px 0;
flex: 1;
display: flex;
justify-content: center;
align-items: center;
border-left: 1px solid #EDEEEF;
color: #4C4D4E;
}
}
.button {
flex: 1;
display: flex;
justify-content: center;
align-items: center;
border: 1px dashed #1677FF;
font-size: 14px;
color: #1677FF;
cursor: pointer;
}
}
}
}
:global {
.ant-popover-inner {
padding: 0 !important;
}
}
.subMenuContent {
display: flex;
flex-direction: row;
align-items: center;
.subButtonGroup {
display: flex;
flex-direction: column;
justify-content: center;
align-items: center;
width: 48px;
min-height: 48px;
border-radius: 24px;
background: #fcfcfc;
font-size: 24px;
padding: 5px;
position: absolute;
left: 90px;
box-shadow: 0 1px 6px #e4e8eb;
.buttonItem {
height: 38px;
width: 38px;
border-radius: 50%;
justify-content: center;
align-items: center;
display: flex;
cursor: pointer;
}
.buttonItem:hover {
background: #EDEEEF;
}
}
}
.subMenuItem {
width: 86px;
height: 49px;
text-align: center;
padding: 12px 2px;
cursor: pointer;
white-space: nowrap;
overflow: hidden;
text-overflow: ellipsis;
border-bottom: 1px solid #EDEEEF;
}

View File

@ -0,0 +1,25 @@
import { WechatPublicInstance } from 'oak-external-sdk';
import { EntityDict } from "../../../oak-app-domain";
import { WebComponentProps } from 'oak-frontend-base';
export default function Render(props: WebComponentProps<EntityDict, keyof EntityDict, false, {
config: any;
menuIndex: number;
file: File;
wechatInstance: WechatPublicInstance;
errorIndex: number[];
menuType: string;
changeConfig: (config: any) => void;
getSelectedBtn: (selectedBtn: number) => void;
getSelectedSubBtn: (selectedSubBtn: number) => void;
getCurrentIndex: (currentIndex: number) => void;
isPreview: boolean;
open: boolean;
}, {
setConfig: (index: number, content: any, currentIndex?: number) => void;
deleteMenuItem: (index: number) => void;
deleteSubMenuItem: (index: number, currentIndex: number) => void;
toRight: (index: number) => void;
toLeft: (index: number) => void;
toUp: (currentIndex: number, index: number) => void;
toDown: (currentIndex: number, index: number) => void;
}>): import("react/jsx-runtime").JSX.Element;

Some files were not shown because too many files have changed in this diff Show More