Skip to content

Commit e752be3

Browse files
fit2cloudwxxfit2-zhao
authored andcommitted
feat: add agent entry for mobile
1 parent f5cf984 commit e752be3

File tree

12 files changed

+204
-11
lines changed

12 files changed

+204
-11
lines changed

frontend/packages/mobile/src/api/modules/index.ts

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
import { showFailToast } from 'vant';
22

33
import createAxios from '@lib/shared/api/http';
4+
import useAgentApi from '@lib/shared/api/modules/agent';
45
import useClueApi from '@lib/shared/api/modules/clue';
56
import useContractApi from '@lib/shared/api/modules/contract';
67
import useCustomerApi from '@lib/shared/api/modules/customer';
@@ -35,6 +36,7 @@ const licenseApi = useLicenseApi(CDR);
3536
const followApi = useFollowApi(CDR);
3637
const contractApi = useContractApi(CDR);
3738
const orderApi = useOrderApi(CDR);
39+
const agentApi = useAgentApi(CDR);
3840

3941
export const {
4042
getFollowPlanDetail,
@@ -408,8 +410,11 @@ export const {
408410
getExportCenterList,
409411
cancelCenterExport,
410412
getConfigSynchronization,
413+
getApiKeyList,
411414
} = businessApi;
412415

413416
export const { isLogin, signout, getKey, login, getThirdOauthCallback, getThirdCallback } = loginApi;
414417

415418
export const { getLicense, addLicense } = licenseApi;
419+
420+
export const { getAgentOptions } = agentApi;
Lines changed: 9 additions & 0 deletions
Loading

frontend/packages/mobile/src/components/business/crm-datasource/index.vue

Lines changed: 7 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -96,20 +96,20 @@
9696
import CrmSelectList from '@/components/business/crm-select-list/index.vue';
9797
9898
import {
99+
getBusinessTitleList,
99100
getCustomerOptions,
100101
getFieldClueList,
101102
getFieldContactList,
103+
getFieldContractList,
104+
getFieldContractPaymentPlanList,
105+
getFieldContractPaymentRecordList,
102106
getFieldCustomerList,
103107
getFieldOpportunityList,
104-
getFieldContractList,
105-
getFieldProductList,
106-
getUserOptions,
108+
getFieldOrderList,
107109
getFieldPriceList,
110+
getFieldProductList,
108111
getFieldQuotationList,
109-
getFieldOrderList,
110-
getFieldContractPaymentPlanList,
111-
getFieldContractPaymentRecordList,
112-
getBusinessTitleList,
112+
getUserOptions,
113113
} from '@/api/modules';
114114
115115
const props = defineProps<{

frontend/packages/mobile/src/components/business/crm-workflow-card/index.vue

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -76,6 +76,7 @@
7676
import { closeToast, showLoadingToast, showSuccessToast } from 'vant';
7777
7878
import { FormDesignKeyEnum } from '@lib/shared/enums/formDesignEnum';
79+
import { ReasonTypeEnum } from '@lib/shared/enums/moduleEnum';
7980
import { useI18n } from '@lib/shared/hooks/useI18n';
8081
import { StageConfigItem } from '@lib/shared/models/opportunity';
8182
@@ -85,7 +86,6 @@
8586
import { hasAllPermission, hasAnyPermission } from '@/utils/permission';
8687
8788
import { CommonRouteEnum } from '@/enums/routeEnum';
88-
import { ReasonTypeEnum } from '@lib/shared/enums/moduleEnum';
8989
9090
const { t } = useI18n();
9191
const router = useRouter();

frontend/packages/mobile/src/components/pure/crm-page-header/index.vue

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,9 @@
33
<template #left>
44
<CrmIcon v-if="!props.hideBack" name="iconicon_chevron_left" width="24px" height="24px" @click="handleBack" />
55
</template>
6+
<template #right>
7+
<slot name="rightSlot" />
8+
</template>
69
</van-nav-bar>
710
</template>
811

frontend/packages/mobile/src/enums/routeEnum.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -47,6 +47,7 @@ export enum MineRouteEnum {
4747
export enum WorkbenchRouteEnum {
4848
WORKBENCH = 'workbench',
4949
WORKBENCH_INDEX = 'workbenchIndex',
50+
WORKBENCH_AGENT = 'workbenchAgent',
5051
WORKBENCH_DUPLICATE_CHECK = 'workbenchDuplicateCheck',
5152
WORKBENCH_DUPLICATE_CHECK_DETAIL = 'workbenchDuplicateCheckDetail',
5253
}

frontend/packages/mobile/src/router/routes/modules/workbench.ts

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -38,6 +38,17 @@ const workbench: AppRouteRecordRaw = {
3838
isCache: true,
3939
},
4040
},
41+
{
42+
path: 'agent',
43+
name: WorkbenchRouteEnum.WORKBENCH_AGENT,
44+
component: () => import('@/views/workbench/agent/index.vue'),
45+
meta: {
46+
locale: '',
47+
permissions: [],
48+
depth: 1,
49+
isCache: true,
50+
},
51+
},
4152
],
4253
};
4354

frontend/packages/mobile/src/store/modules/user/index.ts

Lines changed: 20 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -7,12 +7,14 @@ import { getGenerateId } from '@lib/shared/method';
77
import { clearToken, setToken } from '@lib/shared/method/auth';
88
import { removeRouteListener } from '@lib/shared/method/route-listener';
99
import { removeScript } from '@lib/shared/method/scriptLoader';
10+
import { ApiKeyItem } from '@lib/shared/models/system/business';
1011
import type { LoginParams } from '@lib/shared/models/system/login';
1112
import type { UserInfo } from '@lib/shared/models/user';
1213

13-
import { isLogin, login, signout } from '@/api/modules';
14+
import { getApiKeyList, isLogin, login, signout } from '@/api/modules';
1415
import useUser from '@/hooks/useUser';
1516
import router from '@/router';
17+
import { hasAnyPermission } from '@/utils/permission';
1618

1719
import { AppRouteEnum } from '@/enums/routeEnum';
1820

@@ -22,6 +24,7 @@ export interface UserState {
2224
loginType: string[];
2325
userInfo: UserInfo;
2426
clientIdRandomId: string;
27+
apiKeyList: ApiKeyItem[];
2528
}
2629

2730
const useUserStore = defineStore('user', {
@@ -54,6 +57,7 @@ const useUserStore = defineStore('user', {
5457
defaultPwd: true,
5558
},
5659
clientIdRandomId: '',
60+
apiKeyList: [],
5761
}),
5862

5963
getters: {
@@ -144,6 +148,21 @@ const useUserStore = defineStore('user', {
144148
this.logoutCallBack();
145149
}
146150
},
151+
async initApiKeyList() {
152+
if (!hasAnyPermission(['PERSONAL_API_KEY:READ'])) return;
153+
try {
154+
const res = await getApiKeyList();
155+
this.apiKeyList = res.map((item) => ({
156+
...item,
157+
isExpire: item.forever ? false : item.expireTime < Date.now(),
158+
desensitization: true,
159+
showDescInput: false,
160+
}));
161+
} catch (error) {
162+
// eslint-disable-next-line no-console
163+
console.log(error);
164+
}
165+
},
147166
},
148167
});
149168

Lines changed: 135 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,135 @@
1+
<template>
2+
<div class="flex h-full flex-col overflow-hidden">
3+
<CrmPageHeader :title="selectedAgentName">
4+
<template #rightSlot>
5+
<CrmIcon name="iconview-list" width="24px" height="24px" color="var(--text-n2)" @click="selectAgent" />
6+
</template>
7+
</CrmPageHeader>
8+
<div class="mt-[48px] flex flex-1 flex-col">
9+
<div class="h-full" v-html="activeAgentScript"></div>
10+
</div>
11+
12+
<van-popup v-model:show="showAgent" position="right" :style="{ width: '75%', height: '100%' }">
13+
<CrmPageWrapper :title="t('workbench.agent.select')" hide-back>
14+
<div class="flex h-full flex-col overflow-hidden">
15+
<div class="flex-1 overflow-hidden px-[16px]">
16+
<CrmSelectList
17+
v-model:value="tempActiveAgent"
18+
v-model:selected-rows="selectedRows"
19+
:data="agentList"
20+
:multiple="false"
21+
no-page-nation
22+
/>
23+
</div>
24+
</div>
25+
<template #footer>
26+
<div class="flex items-center gap-[16px]">
27+
<van-button
28+
type="primary"
29+
plain
30+
class="!rounded-[var(--border-radius-small)] !text-[16px]"
31+
block
32+
:disabled="!selectedRows.length"
33+
@click="onConfirm"
34+
>
35+
{{ t('common.confirm') }}
36+
</van-button>
37+
</div>
38+
</template>
39+
</CrmPageWrapper>
40+
</van-popup>
41+
</div>
42+
</template>
43+
44+
<script setup lang="ts">
45+
import { ref } from 'vue';
46+
47+
import { useI18n } from '@lib/shared/hooks/useI18n';
48+
49+
import CrmIcon from '@/components/pure/crm-icon-font/index.vue';
50+
import CrmPageWrapper from '@/components/pure/crm-page-wrapper/index.vue';
51+
import CrmSelectList from '@/components/business/crm-select-list/index.vue';
52+
53+
import { getAgentOptions } from '@/api/modules';
54+
import useUserStore from '@/store/modules/user';
55+
56+
const { t } = useI18n();
57+
58+
const userStore = useUserStore();
59+
const showAgent = ref(false);
60+
61+
const activeAgent = ref<string>(localStorage.getItem('crm-agent-drawer-active-agent') || '');
62+
const tempActiveAgent = ref<string>(activeAgent.value);
63+
const agentList = ref<Record<string, any>[]>([]);
64+
const selectedRows = ref<Record<string, any>[]>([]);
65+
const firstValidApiKey = computed(() => userStore.apiKeyList.find((key) => !key.isExpire && key.enable));
66+
const selectedAgentName = computed(() => agentList.value.find((agent) => agent.id === activeAgent.value)?.name ?? '');
67+
const activeAgentScript = computed(() => {
68+
const script = (agentList.value.find((agent) => agent.id === activeAgent.value)?.script as string) || '';
69+
let result = script.replace(/\$\{ak\}/g, firstValidApiKey.value?.accessKey || '');
70+
result = result.replace(/\$\{sk\}/g, firstValidApiKey.value?.secretKey || '');
71+
result = result.replace(/\$\{username\}/g, userStore.userInfo.name);
72+
return result;
73+
});
74+
75+
function selectAgent() {
76+
tempActiveAgent.value = activeAgent.value;
77+
selectedRows.value = agentList.value.filter((agent) => agent.id === tempActiveAgent.value);
78+
showAgent.value = true;
79+
}
80+
81+
const loading = ref(false);
82+
async function initAgentList() {
83+
try {
84+
loading.value = true;
85+
agentList.value = await getAgentOptions();
86+
87+
const hasAgentId = agentList.value.find((agent) => agent.id === activeAgent.value);
88+
if ((!activeAgent.value && agentList.value.length > 0) || (activeAgent.value && !hasAgentId)) {
89+
activeAgent.value = agentList.value[0]?.id ?? '';
90+
if (activeAgent.value) {
91+
localStorage.setItem('crm-agent-drawer-active-agent', activeAgent.value);
92+
} else {
93+
localStorage.removeItem('crm-agent-drawer-active-agent');
94+
}
95+
} else if (agentList.value.length === 0) {
96+
localStorage.removeItem('crm-agent-drawer-active-agent');
97+
activeAgent.value = '';
98+
}
99+
100+
selectedRows.value = agentList.value.filter((agent) => agent.id === activeAgent.value);
101+
tempActiveAgent.value = activeAgent.value;
102+
} catch (error) {
103+
// eslint-disable-next-line no-console
104+
console.log(error);
105+
} finally {
106+
loading.value = false;
107+
}
108+
}
109+
110+
function onConfirm() {
111+
activeAgent.value = tempActiveAgent.value;
112+
localStorage.setItem('crm-agent-drawer-active-agent', activeAgent.value ?? '');
113+
showAgent.value = false;
114+
}
115+
116+
function initAPIKeyConfig() {
117+
userStore.initApiKeyList();
118+
initAgentList();
119+
}
120+
121+
watch(
122+
() => showAgent.value,
123+
(val) => {
124+
if (val) {
125+
initAPIKeyConfig();
126+
}
127+
}
128+
);
129+
130+
onBeforeMount(() => {
131+
initAPIKeyConfig();
132+
});
133+
</script>
134+
135+
<style scoped></style>

frontend/packages/mobile/src/views/workbench/index.vue

Lines changed: 10 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -11,8 +11,9 @@
1111
class="flex-1 !p-0"
1212
@click="goDuplicateCheck"
1313
/>
14+
<CrmIcon v-if="hasValidApiKey" name="icon-bot" width="21px" height="21px" @click="goAgent" />
1415
<van-badge :dot="showBadge">
15-
<CrmIcon name="iconicon_notification" width="21px" height="21px" @click="goMineMessage" />
16+
<CrmIcon name="iconicon_notification" class="mt-[4px]" width="21px" height="21px" @click="goMineMessage" />
1617
</van-badge>
1718
</div>
1819
<van-notice-bar
@@ -87,7 +88,7 @@
8788
import { lastScopedOptions } from './duplicateCheck/config';
8889
8990
const appStore = useAppStore();
90-
91+
const userStore = useUserStore();
9192
const { t } = useI18n();
9293
const router = useRouter();
9394
@@ -149,6 +150,12 @@
149150
router.push({ name: MineRouteEnum.MINE_MESSAGE });
150151
}
151152
153+
const hasValidApiKey = computed(() => userStore.apiKeyList.some((key) => !key.isExpire && key.enable));
154+
155+
function goAgent() {
156+
router.push({ name: WorkbenchRouteEnum.WORKBENCH_AGENT });
157+
}
158+
152159
function goDuplicateCheck() {
153160
router.push({ name: WorkbenchRouteEnum.WORKBENCH_DUPLICATE_CHECK });
154161
}
@@ -176,6 +183,7 @@
176183
appStore.initMessage();
177184
appStore.connectSystemMessageSSE();
178185
appStore.initStageConfig();
186+
userStore.initApiKeyList();
179187
});
180188
</script>
181189

0 commit comments

Comments
 (0)