mirror of
https://github.com/kuaifan/dootask.git
synced 2025-12-10 18:02:55 +00:00
feat: 添加自定义微应用菜单功能,支持管理员配置和保存菜单项
This commit is contained in:
parent
f65da118d7
commit
4983fe8feb
@ -722,6 +722,47 @@ class SystemController extends AbstractController
|
||||
return Base::retSuccess($type == 'save' ? '保存成功' : 'success', $setting);
|
||||
}
|
||||
|
||||
/**
|
||||
* @api {post} api/system/microapp_menu 自定义应用菜单
|
||||
*
|
||||
* @apiDescription 获取或保存自定义微应用菜单,仅管理员可配置
|
||||
* @apiVersion 1.0.0
|
||||
* @apiGroup system
|
||||
* @apiName microapp_menu
|
||||
*
|
||||
* @apiParam {String} type
|
||||
* - get: 获取(默认)
|
||||
* - save: 保存(限管理员)
|
||||
* @apiParam {Array} list 菜单列表,格式:[{id,name,version,menu_items}]
|
||||
*
|
||||
* @apiSuccess {Number} ret 返回状态码(1正确、0错误)
|
||||
* @apiSuccess {String} msg 返回信息(错误描述)
|
||||
* @apiSuccess {Object} data 返回数据
|
||||
*/
|
||||
public function microapp_menu()
|
||||
{
|
||||
$type = trim(Request::input('type'));
|
||||
$user = User::auth();
|
||||
if ($type == 'save') {
|
||||
User::auth('admin');
|
||||
$list = Request::input('list');
|
||||
if (empty($list) || !is_array($list)) {
|
||||
$list = [];
|
||||
}
|
||||
$apps = Setting::normalizeCustomMicroApps($list);
|
||||
$setting = Base::setting('microapp_menu', $apps);
|
||||
$setting = Setting::formatCustomMicroAppsForResponse($setting);
|
||||
} else {
|
||||
$setting = Base::setting('microapp_menu');
|
||||
if (!is_array($setting)) {
|
||||
$setting = [];
|
||||
}
|
||||
$setting = Setting::filterCustomMicroAppsForUser($setting, $user);
|
||||
$setting = Setting::formatCustomMicroAppsForResponse($setting);
|
||||
}
|
||||
return Base::retSuccess($type == 'save' ? '保存成功' : 'success', $setting);
|
||||
}
|
||||
|
||||
/**
|
||||
* @api {post} api/system/column/template 创建项目模板
|
||||
*
|
||||
|
||||
@ -164,6 +164,213 @@ class Setting extends AbstractModel
|
||||
return $array;
|
||||
}
|
||||
|
||||
/**
|
||||
* 规范自定义微应用配置
|
||||
* @param array $list
|
||||
* @return array
|
||||
*/
|
||||
public static function normalizeCustomMicroApps($list)
|
||||
{
|
||||
if (!is_array($list)) {
|
||||
return [];
|
||||
}
|
||||
$apps = [];
|
||||
foreach ($list as $item) {
|
||||
$app = self::normalizeCustomMicroAppItem($item);
|
||||
if ($app) {
|
||||
$apps[] = $app;
|
||||
}
|
||||
}
|
||||
return $apps;
|
||||
}
|
||||
|
||||
/**
|
||||
* 根据用户身份过滤可见的自定义微应用
|
||||
* @param array $apps
|
||||
* @param \App\Models\User|null $user
|
||||
* @return array
|
||||
*/
|
||||
public static function filterCustomMicroAppsForUser(array $apps, $user)
|
||||
{
|
||||
if (empty($apps)) {
|
||||
return [];
|
||||
}
|
||||
$isAdmin = $user ? $user->isAdmin() : false;
|
||||
$userId = $user ? intval($user->userid) : 0;
|
||||
$filtered = [];
|
||||
foreach ($apps as $app) {
|
||||
$visible = self::normalizeCustomMicroVisible($app['visible_to'] ?? ['admin']);
|
||||
if (!self::isCustomMicroVisibleTo($visible, $isAdmin, $userId)) {
|
||||
continue;
|
||||
}
|
||||
if (empty($app['menu_items']) || !is_array($app['menu_items'])) {
|
||||
continue;
|
||||
}
|
||||
$menus = array_values(array_filter($app['menu_items'], function ($menu) use ($isAdmin, $userId) {
|
||||
if (!isset($menu['visible_to'])) {
|
||||
return true;
|
||||
}
|
||||
$visible = self::normalizeCustomMicroVisible($menu['visible_to']);
|
||||
return self::isCustomMicroVisibleTo($visible, $isAdmin, $userId);
|
||||
}));
|
||||
if (empty($menus)) {
|
||||
continue;
|
||||
}
|
||||
$app['menu_items'] = $menus;
|
||||
$filtered[] = $app;
|
||||
}
|
||||
return $filtered;
|
||||
}
|
||||
|
||||
/**
|
||||
* 将存储结构转换成 appstore 接口同款格式
|
||||
* @param array $apps
|
||||
* @return array
|
||||
*/
|
||||
public static function formatCustomMicroAppsForResponse(array $apps)
|
||||
{
|
||||
return array_values(array_map(function ($app) {
|
||||
unset($app['visible_to']);
|
||||
if (!empty($app['menu_items']) && is_array($app['menu_items'])) {
|
||||
$app['menu_items'] = array_values(array_map(function ($menu) {
|
||||
$menu['keep_alive'] = isset($menu['keep_alive']) ? (bool)$menu['keep_alive'] : true;
|
||||
$menu['disable_scope_css'] = (bool)($menu['disable_scope_css'] ?? false);
|
||||
$menu['auto_dark_theme'] = isset($menu['auto_dark_theme']) ? (bool)$menu['auto_dark_theme'] : true;
|
||||
$menu['transparent'] = (bool)($menu['transparent'] ?? false);
|
||||
if (isset($menu['visible_to'])) {
|
||||
unset($menu['visible_to']);
|
||||
}
|
||||
return $menu;
|
||||
}, $app['menu_items']));
|
||||
}
|
||||
return $app;
|
||||
}, $apps));
|
||||
}
|
||||
|
||||
/**
|
||||
* 规范自定义微应用
|
||||
* @param array $item
|
||||
* @return array|null
|
||||
*/
|
||||
protected static function normalizeCustomMicroAppItem($item)
|
||||
{
|
||||
if (!is_array($item)) {
|
||||
return null;
|
||||
}
|
||||
$id = trim($item['id'] ?? '');
|
||||
if ($id === '') {
|
||||
return null;
|
||||
}
|
||||
$name = Base::newTrim($item['name'] ?? '');
|
||||
$version = Base::newTrim($item['version'] ?? '') ?: 'custom';
|
||||
$menuItems = [];
|
||||
if (isset($item['menu_items']) && is_array($item['menu_items'])) {
|
||||
$menuItems = $item['menu_items'];
|
||||
} elseif (isset($item['menu']) && is_array($item['menu'])) {
|
||||
$menuItems = [$item['menu']];
|
||||
}
|
||||
if (empty($menuItems)) {
|
||||
return null;
|
||||
}
|
||||
$normalizedMenus = [];
|
||||
foreach ($menuItems as $menu) {
|
||||
$formattedMenu = self::normalizeCustomMicroMenuItem($menu, $name ?: $id);
|
||||
if ($formattedMenu) {
|
||||
$normalizedMenus[] = $formattedMenu;
|
||||
}
|
||||
}
|
||||
if (empty($normalizedMenus)) {
|
||||
return null;
|
||||
}
|
||||
return Base::newTrim([
|
||||
'id' => $id,
|
||||
'name' => $name,
|
||||
'version' => $version,
|
||||
'menu_items' => $normalizedMenus,
|
||||
'visible_to' => self::normalizeCustomMicroVisible($item['visible_to'] ?? 'admin'),
|
||||
]);
|
||||
}
|
||||
|
||||
/**
|
||||
* 规范自定义微应用菜单项
|
||||
* @param array $menu
|
||||
* @param string $fallbackLabel
|
||||
* @return array|null
|
||||
*/
|
||||
protected static function normalizeCustomMicroMenuItem($menu, $fallbackLabel = '')
|
||||
{
|
||||
if (!is_array($menu)) {
|
||||
return null;
|
||||
}
|
||||
$url = trim($menu['url'] ?? '');
|
||||
if ($url === '') {
|
||||
return null;
|
||||
}
|
||||
$location = trim($menu['location'] ?? 'application');
|
||||
$label = trim($menu['label'] ?? $fallbackLabel);
|
||||
$urlType = strtolower(trim($menu['url_type'] ?? 'iframe'));
|
||||
$payload = [
|
||||
'location' => $location,
|
||||
'label' => $label,
|
||||
'icon' => Base::newTrim($menu['icon'] ?? ''),
|
||||
'url' => $url,
|
||||
'url_type' => $urlType,
|
||||
'keep_alive' => isset($menu['keep_alive']) ? (bool)$menu['keep_alive'] : true,
|
||||
'disable_scope_css' => (bool)($menu['disable_scope_css'] ?? false),
|
||||
'auto_dark_theme' => isset($menu['auto_dark_theme']) ? (bool)$menu['auto_dark_theme'] : true,
|
||||
'transparent' => (bool)($menu['transparent'] ?? false),
|
||||
];
|
||||
if (!empty($menu['background'])) {
|
||||
$payload['background'] = Base::newTrim($menu['background']);
|
||||
}
|
||||
if (!empty($menu['capsule']) && is_array($menu['capsule'])) {
|
||||
$payload['capsule'] = Base::newTrim($menu['capsule']);
|
||||
}
|
||||
return $payload;
|
||||
}
|
||||
|
||||
/**
|
||||
* 规范自定义微应用可见范围
|
||||
* @param mixed $value
|
||||
* @return array
|
||||
*/
|
||||
protected static function normalizeCustomMicroVisible($value)
|
||||
{
|
||||
if (is_array($value)) {
|
||||
$list = array_filter(array_map('trim', $value));
|
||||
} else {
|
||||
$list = array_filter(array_map('trim', explode(',', (string)$value)));
|
||||
}
|
||||
if (empty($list)) {
|
||||
return ['admin'];
|
||||
}
|
||||
if (in_array('all', $list)) {
|
||||
return ['all'];
|
||||
}
|
||||
return array_values($list);
|
||||
}
|
||||
|
||||
/**
|
||||
* 判断自定义微应用是否可见
|
||||
* @param array $visible
|
||||
* @param bool $isAdmin
|
||||
* @param int $userId
|
||||
* @return bool
|
||||
*/
|
||||
protected static function isCustomMicroVisibleTo(array $visible, bool $isAdmin, int $userId)
|
||||
{
|
||||
if (in_array('all', $visible)) {
|
||||
return true;
|
||||
}
|
||||
if ($isAdmin && in_array('admin', $visible)) {
|
||||
return true;
|
||||
}
|
||||
if ($userId > 0 && in_array((string)$userId, $visible, true)) {
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* 验证邮箱地址(过滤忽略地址)
|
||||
* @param $array
|
||||
|
||||
@ -1301,7 +1301,7 @@ class Base
|
||||
/**
|
||||
* 获取或设置
|
||||
* @param $setname // 配置名称
|
||||
* @param bool $array // 保存内容
|
||||
* @param bool|array $array // 保存内容
|
||||
* @param bool $isUpdate // 保存内容为更新模式,默认否
|
||||
* @return array
|
||||
*/
|
||||
|
||||
@ -15,6 +15,7 @@
|
||||
<DropdownMenu slot="list">
|
||||
<DropdownItem v-if="!sortingMode" name="sort">{{ $L('调整排序') }}</DropdownItem>
|
||||
<DropdownItem v-else name="cancelSort">{{ $L('退出排序') }}</DropdownItem>
|
||||
<DropdownItem v-if="userIsAdmin" divided name="customMicro">{{ $L('自定义应用菜单') }}</DropdownItem>
|
||||
</DropdownMenu>
|
||||
</Dropdown>
|
||||
</div>
|
||||
@ -111,6 +112,114 @@
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!--自定义应用菜单-->
|
||||
<Modal
|
||||
v-if="userIsAdmin"
|
||||
v-model="customMicroModalVisible"
|
||||
:title="$L('自定义应用菜单')"
|
||||
:mask-closable="false"
|
||||
width="760">
|
||||
<Alert type="info" show-icon class="custom-micro-alert">
|
||||
{{ $L('仅管理员可配置,保存后会在应用列表中生成对应菜单。') }}
|
||||
</Alert>
|
||||
<div v-if="customMicroLoading" class="custom-micro-loading">
|
||||
<Loading/>
|
||||
</div>
|
||||
<div v-else class="custom-micro-body">
|
||||
<div v-if="!customMicroMenus.length" class="custom-micro-empty">
|
||||
{{ $L('暂无自定义菜单,请点击下方按钮新增。') }}
|
||||
</div>
|
||||
<Collapse v-else v-model="customMicroCollapsed" accordion simple>
|
||||
<Panel v-for="(item, index) in customMicroMenus" :key="item.uid" :name="item.uid">
|
||||
<div class="custom-micro-card__header">
|
||||
<div class="custom-micro-card__title">
|
||||
{{ item.id || $L('未命名应用') }}
|
||||
</div>
|
||||
<div class="custom-micro-card__actions">
|
||||
<Button @click.stop="duplicateCustomMenu(index)">{{ $L('复制') }}</Button>
|
||||
<Button type="error" @click.stop="removeCustomMenu(index)">{{ $L('删除') }}</Button>
|
||||
</div>
|
||||
</div>
|
||||
<div slot="content">
|
||||
<Form label-position="top">
|
||||
<Row :gutter="16">
|
||||
<Col :sm="12" :xs="24">
|
||||
<FormItem :label="$L('应用 ID')" required>
|
||||
<Input v-model.trim="item.id" placeholder="custom-okr"/>
|
||||
</FormItem>
|
||||
</Col>
|
||||
<Col :sm="12" :xs="24">
|
||||
<FormItem :label="$L('应用名称')">
|
||||
<Input v-model.trim="item.name" placeholder="OKR 开发"/>
|
||||
</FormItem>
|
||||
</Col>
|
||||
</Row>
|
||||
<FormItem :label="$L('菜单标题')" required>
|
||||
<Input v-model.trim="item.menu.label" placeholder="OKR 开发入口"/>
|
||||
</FormItem>
|
||||
<Row :gutter="16">
|
||||
<Col :sm="12" :xs="24">
|
||||
<FormItem :label="$L('菜单位置')">
|
||||
<Select v-model="item.menu.location" transfer>
|
||||
<Option value="application">{{ $L('应用中心 - 常用') }}</Option>
|
||||
<Option value="application/admin">{{ $L('应用中心 - 管理') }}</Option>
|
||||
<Option value="main/menu">{{ $L('主导航') }}</Option>
|
||||
</Select>
|
||||
</FormItem>
|
||||
</Col>
|
||||
<Col :sm="12" :xs="24">
|
||||
<FormItem :label="$L('可见范围')">
|
||||
<Select v-model="item.menu.visible_to" transfer>
|
||||
<Option value="admin">{{ $L('仅管理员') }}</Option>
|
||||
<Option value="all">{{ $L('所有成员') }}</Option>
|
||||
</Select>
|
||||
</FormItem>
|
||||
</Col>
|
||||
</Row>
|
||||
<FormItem :label="$L('图标地址')">
|
||||
<Input v-model.trim="item.menu.icon" placeholder="https://example.com/icon.png"/>
|
||||
</FormItem>
|
||||
<FormItem :label="$L('菜单 URL')" required>
|
||||
<Input v-model.trim="item.menu.url" placeholder="https://example.com/app?token={user_token}"/>
|
||||
</FormItem>
|
||||
<Row :gutter="16">
|
||||
<Col :sm="12" :xs="24">
|
||||
<FormItem :label="$L('URL 类型')">
|
||||
<Select v-model="item.menu.url_type" transfer>
|
||||
<Option value="iframe">iframe</Option>
|
||||
<Option value="iframe_blank">iframe_blank</Option>
|
||||
<Option value="inline">inline</Option>
|
||||
<Option value="inline_blank">inline_blank</Option>
|
||||
<Option value="external">external</Option>
|
||||
</Select>
|
||||
</FormItem>
|
||||
</Col>
|
||||
<Col :sm="12" :xs="24">
|
||||
<FormItem :label="$L('背景颜色')">
|
||||
<Input v-model.trim="item.menu.background" placeholder="#FFFFFF 或 #FFFFFF|#000000"/>
|
||||
</FormItem>
|
||||
</Col>
|
||||
</Row>
|
||||
<div class="custom-micro-checkbox-group">
|
||||
<Checkbox v-model="item.menu.keep_alive">{{ $L('保持激活状态 (keep_alive)') }}</Checkbox>
|
||||
<Checkbox v-model="item.menu.disable_scope_css">{{ $L('禁用作用域样式') }}</Checkbox>
|
||||
<Checkbox v-model="item.menu.transparent">{{ $L('透明背景') }}</Checkbox>
|
||||
<Checkbox v-model="item.menu.auto_dark_theme">{{ $L('自动暗黑模式') }}</Checkbox>
|
||||
</div>
|
||||
</Form>
|
||||
</div>
|
||||
</Panel>
|
||||
</Collapse>
|
||||
<Button class="custom-micro-add-btn" type="dashed" long icon="md-add" @click="addCustomMenu">
|
||||
{{ $L('新增菜单') }}
|
||||
</Button>
|
||||
</div>
|
||||
<div slot="footer" class="adaption">
|
||||
<Button @click="customMicroModalVisible=false">{{ $L('关闭') }}</Button>
|
||||
<Button type="primary" :loading="customMicroSaving" @click="saveCustomMenus">{{ $L('保存') }}</Button>
|
||||
</div>
|
||||
</Modal>
|
||||
|
||||
<!--MY BOT-->
|
||||
<DrawerOverlay v-model="mybotShow" placement="right" :size="720">
|
||||
<template v-if="mybotShow" #title>
|
||||
@ -323,6 +432,20 @@ import ImgUpload from "../../components/ImgUpload.vue";
|
||||
import {webhookEventOptions} from "../../utils/webhook";
|
||||
import Draggable from "vuedraggable";
|
||||
|
||||
const createCustomMicroMenu = () => ({
|
||||
uid: `custom_${Math.random().toString(36).slice(2, 10)}`,
|
||||
id: '',
|
||||
name: '',
|
||||
version: 'custom',
|
||||
menu: {
|
||||
location: 'application',
|
||||
url_type: 'iframe',
|
||||
visible_to: 'admin',
|
||||
keep_alive: true,
|
||||
auto_dark_theme: true,
|
||||
}
|
||||
});
|
||||
|
||||
export default {
|
||||
components: {
|
||||
Draggable,
|
||||
@ -383,6 +506,12 @@ export default {
|
||||
//
|
||||
sendData: [],
|
||||
sendType: '',
|
||||
//
|
||||
customMicroModalVisible: false,
|
||||
customMicroMenus: [],
|
||||
customMicroLoading: false,
|
||||
customMicroSaving: false,
|
||||
customMicroCollapsed: '',
|
||||
}
|
||||
},
|
||||
created() {
|
||||
@ -494,8 +623,123 @@ export default {
|
||||
this.enterSortMode();
|
||||
} else if (action === 'cancelSort') {
|
||||
this.exitSortMode();
|
||||
} else if (action === 'customMicro') {
|
||||
this.openCustomMicroModal();
|
||||
}
|
||||
},
|
||||
openCustomMicroModal() {
|
||||
if (!this.userIsAdmin) {
|
||||
return;
|
||||
}
|
||||
this.customMicroModalVisible = true;
|
||||
this.loadCustomMicroMenus();
|
||||
},
|
||||
loadCustomMicroMenus() {
|
||||
this.customMicroLoading = true;
|
||||
this.$store.dispatch("call", {
|
||||
url: 'system/microapp_menu?type=get',
|
||||
method: 'post',
|
||||
}).then(({data}) => {
|
||||
this.customMicroMenus = this.normalizeCustomMenus(data);
|
||||
this.customMicroCollapsed = this.customMicroMenus.length > 0 ? this.customMicroMenus[0].uid : '';
|
||||
}).catch(({msg}) => {
|
||||
if (msg) {
|
||||
$A.modalError(msg);
|
||||
}
|
||||
}).finally(() => {
|
||||
this.customMicroLoading = false;
|
||||
});
|
||||
},
|
||||
normalizeCustomMenus(list = []) {
|
||||
if (!$A.isArray(list)) {
|
||||
return [];
|
||||
}
|
||||
return list.map(app => {
|
||||
const draft = createCustomMicroMenu();
|
||||
return Object.assign({}, draft, app, {
|
||||
menu: Object.assign({}, draft.menu, $A.isArray(app.menu_items) && app.menu_items.length > 0 ? app.menu_items[0] : {}),
|
||||
});
|
||||
});
|
||||
},
|
||||
pickCustomMenuLabel(label, fallback = '') {
|
||||
if (typeof label === 'string') {
|
||||
return label || fallback;
|
||||
}
|
||||
if ($A.isJson(label)) {
|
||||
return label.zh || label.en || fallback;
|
||||
}
|
||||
return fallback;
|
||||
},
|
||||
addCustomMenu() {
|
||||
const draft = createCustomMicroMenu();
|
||||
this.customMicroMenus.push(draft);
|
||||
this.customMicroCollapsed = draft.uid;
|
||||
},
|
||||
duplicateCustomMenu(index) {
|
||||
const target = this.customMicroMenus[index];
|
||||
if (!target) {
|
||||
return;
|
||||
}
|
||||
const copy = $A.cloneJSON(target);
|
||||
copy.uid = createCustomMicroMenu().uid;
|
||||
copy.id = copy.id ? `${copy.id}_copy` : '';
|
||||
copy.name = copy.name ? `${copy.name} copy` : '';
|
||||
copy.menu.label = copy.menu.label ? `${copy.menu.label} copy` : '';
|
||||
this.customMicroMenus.splice(index + 1, 0, copy);
|
||||
this.customMicroCollapsed = copy.uid;
|
||||
},
|
||||
removeCustomMenu(index) {
|
||||
this.customMicroMenus.splice(index, 1);
|
||||
},
|
||||
saveCustomMenus() {
|
||||
if (this.customMicroSaving) {
|
||||
return;
|
||||
}
|
||||
const payload = [];
|
||||
for (const item of this.customMicroMenus) {
|
||||
const formatted = this.formatCustomMenuForSave(item);
|
||||
if (!formatted) {
|
||||
$A.modalWarning({
|
||||
title: '提示',
|
||||
content: '请为每个菜单填写应用ID、菜单标题和有效的 URL。',
|
||||
});
|
||||
return;
|
||||
}
|
||||
payload.push(formatted);
|
||||
}
|
||||
this.customMicroSaving = true;
|
||||
this.$store.dispatch("call", {
|
||||
url: 'system/microapp_menu?type=save',
|
||||
method: 'post',
|
||||
data: {
|
||||
list: payload
|
||||
},
|
||||
}).then(_ => {
|
||||
$A.messageSuccess('保存成功');
|
||||
this.loadCustomMicroMenus();
|
||||
this.$store.dispatch("updateMicroAppsStatus");
|
||||
}).catch(({msg}) => {
|
||||
if (msg) {
|
||||
$A.modalError(msg);
|
||||
}
|
||||
}).finally(() => {
|
||||
this.customMicroSaving = false;
|
||||
});
|
||||
},
|
||||
formatCustomMenuForSave(item) {
|
||||
const id = (item.id || '').trim();
|
||||
const url = (item.menu.url || '').trim();
|
||||
const label = (item.menu.label || item.name || item.id || '').trim();
|
||||
if (!id || !url || !label) {
|
||||
return null;
|
||||
}
|
||||
return {
|
||||
id,
|
||||
name: (item.name || '').trim(),
|
||||
version: item.version || 'custom',
|
||||
menu_items: [Object.assign({}, item.menu, { url, label })],
|
||||
};
|
||||
},
|
||||
currentCards(type) {
|
||||
return this.sortingMode ? (this.sortLists[type] || []) : this.getDisplayItems(type);
|
||||
},
|
||||
@ -682,9 +926,9 @@ export default {
|
||||
}).then(({data, msg}) => {
|
||||
this.appSorts = this.normalizeSortPayload(data?.sorts || payload);
|
||||
this.exitSortMode();
|
||||
$A.messageSuccess(msg || this.$L('保存成功'));
|
||||
$A.messageSuccess(msg || '保存成功');
|
||||
}).catch(({msg}) => {
|
||||
$A.modalError(msg || this.$L('保存失败'));
|
||||
$A.modalError(msg || '保存失败');
|
||||
}).finally(() => {
|
||||
this.appSortSaving = false;
|
||||
});
|
||||
@ -876,7 +1120,7 @@ export default {
|
||||
// 与我的机器人聊天
|
||||
chatMybot(userid) {
|
||||
this.$store.dispatch("openDialogUserid", userid).catch(({msg}) => {
|
||||
$A.modalError(msg || this.$L('打开会话失败'))
|
||||
$A.modalError(msg || '打开会话失败')
|
||||
});
|
||||
},
|
||||
// 添加修改我的机器人
|
||||
@ -985,7 +1229,7 @@ export default {
|
||||
} else {
|
||||
// 其他文本
|
||||
$A.modalInfo({
|
||||
title: this.$L('扫描结果'),
|
||||
title: '扫描结果',
|
||||
content: text,
|
||||
width: 400,
|
||||
});
|
||||
|
||||
20
resources/assets/js/store/actions.js
vendored
20
resources/assets/js/store/actions.js
vendored
@ -5144,7 +5144,7 @@ export default {
|
||||
* @param commit
|
||||
* @param dispatch
|
||||
*/
|
||||
async updateMicroAppsStatus({commit, state}) {
|
||||
async updateMicroAppsStatus({commit, state, dispatch}) {
|
||||
const {data: {code, data}} = await axios.get($A.mainUrl('appstore/api/v1/internal/installed'), {
|
||||
headers: {
|
||||
Token: state.userToken,
|
||||
@ -5152,7 +5152,23 @@ export default {
|
||||
}
|
||||
})
|
||||
if (code === 200) {
|
||||
commit("microApps/data", data|| [])
|
||||
let apps = Array.isArray(data) ? data : [];
|
||||
try {
|
||||
const {data: customData} = await dispatch('call', {
|
||||
url: 'system/microapp_menu?type=get',
|
||||
});
|
||||
if ($A.isArray(customData) && customData.length > 0) {
|
||||
customData.forEach(item => {
|
||||
item.menu_items.forEach(menu => {
|
||||
menu.icon = menu.icon || $A.mainUrl("images/application/appstore-default.svg");
|
||||
});
|
||||
});
|
||||
apps = apps.concat(customData);
|
||||
}
|
||||
} catch (e) {
|
||||
// 忽略自定义菜单加载失败
|
||||
}
|
||||
commit("microApps/data", apps || [])
|
||||
}
|
||||
},
|
||||
|
||||
|
||||
4
resources/assets/js/store/mutations.js
vendored
4
resources/assets/js/store/mutations.js
vendored
@ -420,8 +420,8 @@ export default {
|
||||
// 更新菜单
|
||||
const menus = [];
|
||||
data.forEach((item) => {
|
||||
if (item.menu_items) {
|
||||
menus.push(...item.menu_items.map(m => Object.assign(m, {id: item.id})));
|
||||
if (Array.isArray(item.menu_items) && item.menu_items.length > 0) {
|
||||
menus.push(...item.menu_items.map(menu => Object.assign({}, menu, {id: item.id})));
|
||||
}
|
||||
})
|
||||
menus.forEach(item => {
|
||||
|
||||
80
resources/assets/sass/pages/page-apply.scss
vendored
80
resources/assets/sass/pages/page-apply.scss
vendored
@ -582,6 +582,86 @@
|
||||
}
|
||||
}
|
||||
|
||||
.custom-micro-alert {
|
||||
margin-bottom: 16px;
|
||||
}
|
||||
|
||||
.custom-micro-loading {
|
||||
min-height: 160px;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
}
|
||||
|
||||
.custom-micro-body {
|
||||
margin: 0 -24px;
|
||||
padding: 0 24px;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
gap: 16px;
|
||||
|
||||
.ivu-collapse {
|
||||
> .ivu-collapse-item {
|
||||
> .ivu-collapse-header {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
height: 60px;
|
||||
padding-left: 0
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.custom-micro-empty {
|
||||
text-align: center;
|
||||
color: #909399;
|
||||
padding: 40px 0;
|
||||
}
|
||||
|
||||
.custom-micro-card {
|
||||
border: 1px solid #e5e6eb;
|
||||
border-radius: 8px;
|
||||
padding: 16px;
|
||||
background-color: #fff;
|
||||
}
|
||||
|
||||
.custom-micro-card__header {
|
||||
flex: 1;
|
||||
min-width: 0;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: space-between;
|
||||
|
||||
.custom-micro-card__title {
|
||||
font-weight: 600;
|
||||
font-size: 15px;
|
||||
color: #333;
|
||||
}
|
||||
|
||||
.custom-micro-card__actions {
|
||||
display: flex;
|
||||
gap: 8px;
|
||||
|
||||
.ivu-btn {
|
||||
font-size: 13px;
|
||||
padding: 0 10px;
|
||||
height: 28px;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.custom-micro-checkbox-group {
|
||||
display: flex;
|
||||
flex-wrap: wrap;
|
||||
gap: 12px 24px;
|
||||
margin-top: 8px;
|
||||
}
|
||||
|
||||
.custom-micro-add-btn {
|
||||
flex-shrink: 0;
|
||||
height: 38px;
|
||||
}
|
||||
|
||||
body.window-portrait {
|
||||
.page-apply {
|
||||
.apply-wrapper {
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user