Pre Merge pull request !159 from xingyu/dev
commit
9e8cd2020e
|
@ -305,7 +305,7 @@ onMounted(async () => {
|
|||
<template>
|
||||
<Layout.Sider
|
||||
width="280px"
|
||||
class="!bg-primary-foreground conversation-container relative flex h-full flex-col justify-between overflow-hidden p-4"
|
||||
class="conversation-container relative flex h-full flex-col justify-between overflow-hidden p-4"
|
||||
>
|
||||
<Drawer />
|
||||
<!-- 左顶部:对话 -->
|
||||
|
@ -358,7 +358,9 @@ onMounted(async () => {
|
|||
<div
|
||||
class="conversation flex cursor-pointer flex-row items-center justify-between rounded-lg px-2 leading-10"
|
||||
:class="[
|
||||
conversation.id === activeConversationId ? 'bg-gray-100' : '',
|
||||
conversation.id === activeConversationId
|
||||
? 'bg-primary-200'
|
||||
: '',
|
||||
]"
|
||||
>
|
||||
<div class="title-wrapper flex items-center">
|
||||
|
@ -418,7 +420,7 @@ onMounted(async () => {
|
|||
|
||||
<!-- 左底部:工具栏 -->
|
||||
<div
|
||||
class="absolute bottom-1 left-0 right-0 mb-4 flex items-center justify-between bg-gray-50 px-5 leading-9 text-gray-400 shadow-sm"
|
||||
class="bg-card absolute bottom-1 left-0 right-0 mb-4 flex items-center justify-between px-5 leading-9 text-gray-400 shadow-sm"
|
||||
>
|
||||
<div
|
||||
class="flex cursor-pointer items-center text-gray-400"
|
||||
|
|
|
@ -79,7 +79,7 @@ async function handleTabsScroll() {
|
|||
}"
|
||||
>
|
||||
<!-- 更多操作 -->
|
||||
<div v-if="showMore" class="absolute right-3 top-0">
|
||||
<div v-if="showMore" class="absolute right-2 top-0">
|
||||
<Dropdown>
|
||||
<Button type="link">
|
||||
<IconifyIcon icon="lucide:ellipsis-vertical" />
|
||||
|
@ -89,7 +89,7 @@ async function handleTabsScroll() {
|
|||
<Menu.Item @click="handleMoreClick(['edit', role])">
|
||||
<div class="flex items-center">
|
||||
<IconifyIcon icon="lucide:edit" color="#787878" />
|
||||
<span>编辑</span>
|
||||
<span class="text-primary">编辑</span>
|
||||
</div>
|
||||
</Menu.Item>
|
||||
<Menu.Item @click="handleMoreClick(['delete', role])">
|
||||
|
@ -108,12 +108,12 @@ async function handleTabsScroll() {
|
|||
<Avatar :src="role.avatar" class="h-10 w-10 overflow-hidden" />
|
||||
</div>
|
||||
|
||||
<div class="ml-2 w-full">
|
||||
<div class="ml-2 w-4/5">
|
||||
<div class="h-20">
|
||||
<div class="max-w-36 text-lg font-bold text-gray-600">
|
||||
<div class="max-w-32 text-lg font-bold">
|
||||
{{ role.name }}
|
||||
</div>
|
||||
<div class="mt-2 text-sm text-gray-400">
|
||||
<div class="mt-2 text-sm">
|
||||
{{ role.description }}
|
||||
</div>
|
||||
</div>
|
||||
|
|
|
@ -174,7 +174,7 @@ onMounted(async () => {
|
|||
<template>
|
||||
<Drawer>
|
||||
<Layout
|
||||
class="absolute inset-0 flex h-full w-full flex-col overflow-hidden bg-white"
|
||||
class="bg-card absolute inset-0 flex h-full w-full flex-col overflow-hidden"
|
||||
>
|
||||
<FormModal @success="handlerAddRoleSuccess" />
|
||||
|
||||
|
|
|
@ -495,6 +495,7 @@ onMounted(async () => {
|
|||
<Layout class="absolute left-0 top-0 m-4 h-full w-full flex-1">
|
||||
<!-- 左侧:对话列表 -->
|
||||
<ConversationList
|
||||
class="!bg-card"
|
||||
:active-id="activeConversationId as any"
|
||||
ref="conversationListRef"
|
||||
@on-conversation-create="handleConversationCreateSuccess"
|
||||
|
@ -504,9 +505,9 @@ onMounted(async () => {
|
|||
/>
|
||||
|
||||
<!-- 右侧:详情部分 -->
|
||||
<Layout class="mx-4 bg-white">
|
||||
<Layout class="bg-card mx-4">
|
||||
<Layout.Header
|
||||
class="flex items-center justify-between !bg-gray-50 shadow-none"
|
||||
class="!bg-card border-border flex items-center justify-between border-b"
|
||||
>
|
||||
<div class="text-lg font-bold">
|
||||
{{ activeConversation?.title ? activeConversation?.title : '对话' }}
|
||||
|
@ -565,9 +566,9 @@ onMounted(async () => {
|
|||
</div>
|
||||
</Layout.Content>
|
||||
|
||||
<Layout.Footer class="m-0 flex flex-col !bg-white p-0">
|
||||
<Layout.Footer class="!bg-card m-0 flex flex-col p-0">
|
||||
<form
|
||||
class="my-5 mb-5 mt-2 flex flex-col rounded-xl border border-gray-200 px-2 py-2.5"
|
||||
class="border-border my-5 mb-5 mt-2 flex flex-col rounded-xl border px-2 py-2.5"
|
||||
>
|
||||
<textarea
|
||||
class="box-border h-24 resize-none overflow-auto border-none px-0 py-1 focus:outline-none"
|
||||
|
|
|
@ -90,9 +90,9 @@ onMounted(async () => {
|
|||
|
||||
<template>
|
||||
<Page auto-content-height>
|
||||
<div class="bg-card absolute inset-0 flex h-full w-full flex-row">
|
||||
<div class="left-0 flex w-96 flex-col p-4">
|
||||
<div class="segmented flex justify-center">
|
||||
<div class="absolute inset-0 m-4 flex h-full w-full flex-row">
|
||||
<div class="bg-card left-0 mr-4 flex w-96 flex-col rounded-lg p-4">
|
||||
<div class="flex justify-center">
|
||||
<Segmented
|
||||
v-model:value="selectPlatform"
|
||||
:options="platformOptions"
|
||||
|
@ -125,7 +125,7 @@ onMounted(async () => {
|
|||
/>
|
||||
</div>
|
||||
</div>
|
||||
<div class="bg-card ml-4 flex-1">
|
||||
<div class="bg-card flex-1">
|
||||
<ImageList ref="imageListRef" @on-regeneration="handleRegeneration" />
|
||||
</div>
|
||||
</div>
|
||||
|
|
|
@ -123,8 +123,10 @@ function submit() {
|
|||
<template>
|
||||
<DefineTab v-slot="{ active, text, itemClick }">
|
||||
<span
|
||||
:class="active ? 'text-black shadow-md' : 'hover:bg-gray-200'"
|
||||
class="relative z-10 inline-block w-1/2 cursor-pointer rounded-full text-center leading-7 text-gray-400 hover:text-black"
|
||||
:class="
|
||||
active ? 'bg-primary-600 text-white shadow-md' : 'hover:bg-primary-200'
|
||||
"
|
||||
class="relative z-10 inline-block w-1/2 cursor-pointer rounded-full text-center leading-7 hover:text-black"
|
||||
@click="itemClick"
|
||||
>
|
||||
{{ text }}
|
||||
|
@ -136,7 +138,7 @@ function submit() {
|
|||
<span>{{ label }}</span>
|
||||
<span
|
||||
v-if="hint"
|
||||
class="flex cursor-pointer select-none items-center text-xs text-purple-500"
|
||||
class="text-primary-500 flex cursor-pointer select-none items-center text-xs"
|
||||
@click="hintClick"
|
||||
>
|
||||
<IconifyIcon icon="lucide:circle-help" />
|
||||
|
@ -145,14 +147,14 @@ function submit() {
|
|||
</h3>
|
||||
</DefineLabel>
|
||||
<div class="flex flex-col" v-bind="$attrs">
|
||||
<div class="flex w-full justify-center bg-gray-50 pt-2">
|
||||
<div class="z-10 w-72 rounded-full bg-gray-200 p-1">
|
||||
<div class="bg-card flex w-full justify-center pt-2">
|
||||
<div class="bg-card z-10 w-72 rounded-full p-1">
|
||||
<div
|
||||
:class="
|
||||
selectedTab === AiWriteTypeEnum.REPLY &&
|
||||
'after:translate-x-[100%] after:transform'
|
||||
"
|
||||
class="relative flex items-center after:absolute after:left-0 after:top-0 after:block after:h-7 after:w-1/2 after:rounded-full after:bg-white after:transition-transform after:content-['']"
|
||||
class="after:bg-card relative flex items-center after:absolute after:left-0 after:top-0 after:block after:h-7 after:w-1/2 after:rounded-full after:transition-transform after:content-['']"
|
||||
>
|
||||
<ReuseTab
|
||||
v-for="tab in tabs"
|
||||
|
@ -166,7 +168,7 @@ function submit() {
|
|||
</div>
|
||||
</div>
|
||||
<div
|
||||
class="box-border h-full w-96 flex-grow overflow-y-auto bg-gray-50 px-7 pb-2 lg:block"
|
||||
class="bg-card box-border h-full w-96 flex-grow overflow-y-auto px-7 pb-2 lg:block"
|
||||
>
|
||||
<div>
|
||||
<template v-if="selectedTab === 1">
|
||||
|
@ -233,11 +235,7 @@ function submit() {
|
|||
<Button :disabled="isWriting" class="mr-2" @click="reset">
|
||||
重置
|
||||
</Button>
|
||||
<Button
|
||||
:loading="isWriting"
|
||||
class="bg-purple-500 text-white"
|
||||
@click="submit"
|
||||
>
|
||||
<Button type="primary" :loading="isWriting" @click="submit">
|
||||
生成
|
||||
</Button>
|
||||
</div>
|
||||
|
|
|
@ -54,22 +54,18 @@ watch(copied, (val) => {
|
|||
});
|
||||
</script>
|
||||
<template>
|
||||
<Card class="my-card flex h-full flex-col">
|
||||
<Card class="flex h-full flex-col">
|
||||
<template #title>
|
||||
<h3 class="m-0 flex shrink-0 items-center justify-between px-7">
|
||||
<span>预览</span>
|
||||
<!-- 展示在右上角 -->
|
||||
<Button
|
||||
class="flex bg-purple-500 text-white"
|
||||
type="primary"
|
||||
v-show="showCopy"
|
||||
@click="copyContent"
|
||||
size="small"
|
||||
>
|
||||
<template #icon>
|
||||
<div class="flex items-center justify-center">
|
||||
<IconifyIcon icon="lucide:copy" />
|
||||
</div>
|
||||
</template>
|
||||
复制
|
||||
</Button>
|
||||
</h3>
|
||||
|
@ -79,7 +75,7 @@ watch(copied, (val) => {
|
|||
class="hide-scroll-bar box-border h-full overflow-y-auto"
|
||||
>
|
||||
<div
|
||||
class="relative box-border min-h-full w-full flex-grow bg-white p-3 sm:p-7"
|
||||
class="bg-card relative box-border min-h-full w-full flex-grow p-3 sm:p-7"
|
||||
>
|
||||
<!-- 终止生成内容的按钮 -->
|
||||
<Button
|
||||
|
|
|
@ -21,8 +21,10 @@ const emits = defineEmits<{
|
|||
<span
|
||||
v-for="tag in props.tags"
|
||||
:key="tag.value"
|
||||
class="mb-2 cursor-pointer rounded border-2 border-solid border-gray-200 bg-gray-200 px-1 text-xs leading-6"
|
||||
:class="modelValue === tag.value && '!border-purple-500 !text-purple-500'"
|
||||
class="bg-card border-card-100 mb-2 cursor-pointer rounded border-2 border-solid px-1 text-xs leading-6"
|
||||
:class="
|
||||
modelValue === tag.value && '!border-primary-500 !text-primary-500'
|
||||
"
|
||||
@click="emits('update:modelValue', tag.value)"
|
||||
>
|
||||
{{ tag.label }}
|
||||
|
|
|
@ -66,10 +66,10 @@ function reset() {
|
|||
|
||||
<template>
|
||||
<Page auto-content-height>
|
||||
<div class="absolute bottom-0 left-0 right-0 top-0 flex">
|
||||
<div class="absolute bottom-0 left-0 right-0 top-0 m-4 flex">
|
||||
<Left
|
||||
:is-writing="isWriting"
|
||||
class="h-full"
|
||||
class="mr-4 h-full rounded-lg"
|
||||
@submit="submit"
|
||||
@reset="reset"
|
||||
@example="handleExampleClick"
|
||||
|
|
|
@ -8,13 +8,20 @@ import { useRoute, useRouter } from 'vue-router';
|
|||
import { confirm, Page, useVbenModal } from '@vben/common-ui';
|
||||
import { useTabs } from '@vben/hooks';
|
||||
|
||||
import { Button, Card, message, Tabs } from 'ant-design-vue';
|
||||
import { Card, message, Tabs } from 'ant-design-vue';
|
||||
|
||||
import { getCustomer, updateCustomerDealStatus } from '#/api/crm/customer';
|
||||
import {
|
||||
getCustomer,
|
||||
lockCustomer,
|
||||
putCustomerPool,
|
||||
receiveCustomer,
|
||||
updateCustomerDealStatus,
|
||||
} from '#/api/crm/customer';
|
||||
import { getOperateLogPage } from '#/api/crm/operateLog';
|
||||
import { BizTypeEnum } from '#/api/crm/permission';
|
||||
import { useDescription } from '#/components/description';
|
||||
import { AsyncOperateLog } from '#/components/operate-log';
|
||||
import { ACTION_ICON, TableAction } from '#/components/table-action';
|
||||
import { BusinessDetailsList } from '#/views/crm/business';
|
||||
import { ContactDetailsList } from '#/views/crm/contact';
|
||||
import { ContractDetailsList } from '#/views/crm/contract';
|
||||
|
@ -99,18 +106,45 @@ function handleTransfer() {
|
|||
}
|
||||
|
||||
/** 锁定客户 */
|
||||
function handleLock() {
|
||||
transferModalApi.setData({ id: customerId.value }).open();
|
||||
}
|
||||
|
||||
/** 解锁客户 */
|
||||
function handleUnlock() {
|
||||
transferModalApi.setData({ id: customerId.value }).open();
|
||||
function handleLock(lockStatus: boolean): Promise<boolean | undefined> {
|
||||
return new Promise((resolve, reject) => {
|
||||
confirm({
|
||||
content: `确定锁定客户【${customer.value.name}】吗?`,
|
||||
})
|
||||
.then(async () => {
|
||||
const res = await lockCustomer(customerId.value, lockStatus);
|
||||
if (res) {
|
||||
message.success(lockStatus ? '锁定客户成功' : '解锁客户成功');
|
||||
resolve(true);
|
||||
} else {
|
||||
reject(new Error(lockStatus ? '锁定客户失败' : '解锁客户失败'));
|
||||
}
|
||||
})
|
||||
.catch(() => {
|
||||
reject(new Error('取消操作'));
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
/** 领取客户 */
|
||||
function handleReceive() {
|
||||
transferModalApi.setData({ id: customerId.value }).open();
|
||||
function handleReceive(): Promise<boolean | undefined> {
|
||||
return new Promise((resolve, reject) => {
|
||||
confirm({
|
||||
content: `确定领取客户【${customer.value.name}】吗?`,
|
||||
})
|
||||
.then(async () => {
|
||||
const res = await receiveCustomer([customerId.value]);
|
||||
if (res) {
|
||||
message.success('领取客户成功');
|
||||
resolve(true);
|
||||
} else {
|
||||
reject(new Error('领取客户失败'));
|
||||
}
|
||||
})
|
||||
.catch(() => {
|
||||
reject(new Error('取消操作'));
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
/** 分配客户 */
|
||||
|
@ -119,8 +153,24 @@ function handleDistributeForm() {
|
|||
}
|
||||
|
||||
/** 客户放入公海 */
|
||||
function handlePutPool() {
|
||||
transferModalApi.setData({ id: customerId.value }).open();
|
||||
function handlePutPool(): Promise<boolean | undefined> {
|
||||
return new Promise((resolve, reject) => {
|
||||
confirm({
|
||||
content: `确定将客户【${customer.value.name}】放入公海吗?`,
|
||||
})
|
||||
.then(async () => {
|
||||
const res = await putCustomerPool(customerId.value);
|
||||
if (res) {
|
||||
message.success('放入公海成功');
|
||||
resolve(true);
|
||||
} else {
|
||||
reject(new Error('放入公海失败'));
|
||||
}
|
||||
})
|
||||
.catch(() => {
|
||||
reject(new Error('取消操作'));
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
/** 更新成交状态操作 */
|
||||
|
@ -161,61 +211,62 @@ onMounted(() => {
|
|||
<TransferModal @success="loadCustomerDetail" />
|
||||
<DistributeModal @success="loadCustomerDetail" />
|
||||
<template #extra>
|
||||
<div class="flex items-center gap-2">
|
||||
<Button
|
||||
v-if="permissionListRef?.validateWrite"
|
||||
type="primary"
|
||||
@click="handleEdit"
|
||||
v-access:code="['crm:customer:update']"
|
||||
>
|
||||
{{ $t('ui.actionTitle.edit') }}
|
||||
</Button>
|
||||
<Button
|
||||
v-if="permissionListRef?.validateOwnerUser"
|
||||
type="primary"
|
||||
@click="handleTransfer"
|
||||
>
|
||||
转移
|
||||
</Button>
|
||||
<Button
|
||||
v-if="permissionListRef?.validateWrite"
|
||||
@click="handleUpdateDealStatus"
|
||||
>
|
||||
更改成交状态
|
||||
</Button>
|
||||
<Button
|
||||
v-if="customer.lockStatus && permissionListRef?.validateOwnerUser"
|
||||
@click="handleUnlock"
|
||||
>
|
||||
解锁
|
||||
</Button>
|
||||
<Button
|
||||
v-if="!customer.lockStatus && permissionListRef?.validateOwnerUser"
|
||||
@click="handleLock"
|
||||
>
|
||||
锁定
|
||||
</Button>
|
||||
<Button
|
||||
v-if="!customer.ownerUserId"
|
||||
type="primary"
|
||||
@click="handleReceive"
|
||||
>
|
||||
领取
|
||||
</Button>
|
||||
<Button
|
||||
v-if="!customer.ownerUserId"
|
||||
type="primary"
|
||||
@click="handleDistributeForm"
|
||||
>
|
||||
分配
|
||||
</Button>
|
||||
<Button
|
||||
v-if="customer.ownerUserId && permissionListRef?.validateOwnerUser"
|
||||
@click="handlePutPool"
|
||||
>
|
||||
放入公海
|
||||
</Button>
|
||||
</div>
|
||||
<TableAction
|
||||
:actions="[
|
||||
{
|
||||
label: $t('ui.actionTitle.edit'),
|
||||
type: 'primary',
|
||||
icon: ACTION_ICON.EDIT,
|
||||
auth: ['crm:customer:update'],
|
||||
ifShow: permissionListRef?.validateWrite,
|
||||
onClick: handleEdit,
|
||||
},
|
||||
{
|
||||
label: '转移',
|
||||
type: 'primary',
|
||||
ifShow: permissionListRef?.validateOwnerUser,
|
||||
onClick: handleTransfer,
|
||||
},
|
||||
{
|
||||
label: '更改成交状态',
|
||||
type: 'default',
|
||||
ifShow: permissionListRef?.validateWrite,
|
||||
onClick: handleUpdateDealStatus,
|
||||
},
|
||||
{
|
||||
label: '锁定',
|
||||
type: 'default',
|
||||
ifShow:
|
||||
!customer.lockStatus && permissionListRef?.validateOwnerUser,
|
||||
onClick: handleLock.bind(null, true),
|
||||
},
|
||||
{
|
||||
label: '解锁',
|
||||
type: 'default',
|
||||
ifShow: customer.lockStatus && permissionListRef?.validateOwnerUser,
|
||||
onClick: handleLock.bind(null, false),
|
||||
},
|
||||
{
|
||||
label: '领取',
|
||||
type: 'primary',
|
||||
ifShow: !customer.ownerUserId,
|
||||
onClick: handleReceive,
|
||||
},
|
||||
{
|
||||
label: '分配',
|
||||
type: 'default',
|
||||
ifShow: !customer.ownerUserId,
|
||||
onClick: handleDistributeForm,
|
||||
},
|
||||
{
|
||||
label: '放入公海',
|
||||
type: 'default',
|
||||
ifShow:
|
||||
!!customer.ownerUserId && permissionListRef?.validateOwnerUser,
|
||||
onClick: handlePutPool,
|
||||
},
|
||||
]"
|
||||
/>
|
||||
</template>
|
||||
<Card class="min-h-[10%]">
|
||||
<Description :data="customer" />
|
||||
|
|
|
@ -78,7 +78,7 @@ export function useFormSchema(): VbenFormSchema[] {
|
|||
options: contracts.map((item) => ({
|
||||
label: item.name,
|
||||
value: item.id,
|
||||
disabled: item.auditStatus === 20,
|
||||
disabled: item.auditStatus !== 20,
|
||||
})),
|
||||
placeholder: '请选择合同',
|
||||
} as any;
|
||||
|
|
Loading…
Reference in New Issue