| | |
| | | <a-select |
| | | v-model:value="tagsValue" |
| | | mode="multiple" |
| | | style="width: 300px" |
| | | style="width: 36px" |
| | | :searchValue="name" |
| | | :labelInValue="true" |
| | | :defaultOpen="false" |
| | | :bordered="false" |
| | | :showSearch="false" |
| | | :dropdownMatchSelectWidth="false" |
| | | :options="items.map(item => ({ value: item.name, label: item.name, color: item.color}))" |
| | | > |
| | | <template #option="{ value, color }"> |
| | |
| | | </template> |
| | | 新建标签 |
| | | </a-button> |
| | | <SettingOutlined class="cursor-pointer" /> |
| | | </a-space> |
| | | <a-divider style="margin: 4px 0" /> |
| | | <v-nodes :vnodes="menu" /> |
| | |
| | | |
| | | </template> |
| | | <script lang="ts" setup> |
| | | import { PlusOutlined } from '@ant-design/icons-vue'; |
| | | import { PlusOutlined,SettingOutlined } from '@ant-design/icons-vue'; |
| | | import { defineComponent, ref } from 'vue'; |
| | | import Icon from "@/components/Icon/Icon.vue"; |
| | | const prefixCls = 'tag-selector'; |
| | |
| | | @click="" |
| | | :size="20" |
| | | /> |
| | | <Icon |
| | | icon="ri:more-2-fill" |
| | | class="cursor-pointer" |
| | | @click="" |
| | | :size="20" |
| | | /> |
| | | <a-dropdown :trigger="['click']"> |
| | | <Icon |
| | | icon="ri:more-2-fill" |
| | | class="cursor-pointer" |
| | | @click="" |
| | | :size="20" |
| | | /> |
| | | <template #overlay> |
| | | <a-menu> |
| | | <a-menu-item key="0"> |
| | | <span >转移</span> |
| | | </a-menu-item> |
| | | <a-menu-item key="1" @click="handleReallocate"> |
| | | <span>重新分配</span> |
| | | </a-menu-item> |
| | | <!-- <a-menu-divider />--> |
| | | <a-menu-item key="2">合并线索</a-menu-item> |
| | | <a-menu-item key="3">无效</a-menu-item> |
| | | <a-menu-item key="4">删除</a-menu-item> |
| | | </a-menu> |
| | | </template> |
| | | </a-dropdown> |
| | | </div> |
| | | |
| | | </template> |
| | |
| | | import Icon from "@/components/Icon/Icon.vue"; |
| | | import {Tooltip} from "ant-design-vue"; |
| | | import Content from "./drawer/index.vue"; |
| | | import EventBus from "@/utils/eventBus"; |
| | | import {reactive, defineEmits} from 'vue'; |
| | | |
| | | const emit = defineEmits(['success', 'register']); |
| | | |
| | |
| | | // }); |
| | | |
| | | // const [registerDrawer] = useDrawer(); |
| | | |
| | | let currentClues = reactive({}); |
| | | const [registerDrawer] = useDrawerInner((data) => { |
| | | Logger.log('Drawer 注册回调', data); |
| | | currentClues = data.clue; |
| | | // // 方式1 |
| | | // setFieldsValue({ |
| | | // field2: data.data, |
| | |
| | | // }); |
| | | }); |
| | | |
| | | // function handleRowClick(e) { |
| | | // Logger.log('handleRowClick',e) |
| | | // openDrawer(true, { |
| | | // isUpdate: false, |
| | | // }); |
| | | // } |
| | | function handleReallocate() { |
| | | Logger.log('点击了重新分配', currentClues); |
| | | EventBus.emit('openReallocateModal', currentClues); |
| | | } |
| | | |
| | | |
| | | </script> |
| | |
| | | console.log('cancel'); |
| | | } |
| | | |
| | | function handleRowClick(e) { |
| | | Logger.log('handleRowClick', e); |
| | | function handleRowClick(data) { |
| | | Logger.log('handleRowClick', data); |
| | | openDrawer(true, { |
| | | isUpdate: false, |
| | | clue: data |
| | | }); |
| | | } |
| | | |
| | |
| | | {{ tag }} |
| | | </Tag> |
| | | </template> |
| | | <TagSelector class="pb-10px"></TagSelector> |
| | | <a-popconfirm title="Title" > |
| | | <Icon |
| | | icon="uil:focus-add" |
| | | class="mr-15px cursor-pointer" |
| | | @click="" |
| | | :style="{ color: 'hotpink' }" |
| | | :size="20" |
| | | /> |
| | | <template #description> |
| | | |
| | | </template> |
| | | </a-popconfirm> |
| | | <!-- <a-dropdown :trigger="['click']">--> |
| | | <!-- <template #overlay>--> |
| | | <!-- <TagSelector></TagSelector>--> |
| | | <!-- </template>--> |
| | | <!-- </a-dropdown>--> |
| | | <TagSelector class="pb-10px inline-block mt-10px"></TagSelector> |
| | | </div> |
| | | |
| | | </Col> |
| | |
| | | |
| | | import { FormProps, BasicColumn } from '@/components/Table'; |
| | | import {treeOptionsListApi} from "@/api/demo/tree"; |
| | | import {getAdvanceSchema} from "@/views/customer/components/tableData"; |
| | | |
| | | export function getEditCellColumns(): BasicColumn[] { |
| | | return [ |
| | |
| | | export function getFormConfig(): Partial<FormProps> { |
| | | return { |
| | | labelWidth: 100, |
| | | layout: 'horizontal', |
| | | rowProps: { |
| | | justify: 'end', |
| | | }, |
| | | showResetButton: false, |
| | | showSubmitButton: false, |
| | | schemas: [ |
| | | ...getAdvanceSchema(1), |
| | | { |
| | | field: `field11`, |
| | | label: ``, |
| | | slot: 'custom', |
| | | label: `搜索`, |
| | | component: 'Input', |
| | | colProps: { |
| | | xl: 12, |
| | | xxl: 8, |
| | |
| | | </Pane> |
| | | <Pane min-size="50" size="88"> |
| | | <ScrollContainer class="p-8"> |
| | | <TagSelector></TagSelector> |
| | | <!-- <div><a-button class="mr-2" type="primary" shape="round" @click="openModal1"> 新建日程 </a-button></div>--> |
| | | <!-- <div><a-button class="mr-2" type="primary" shape="round" @click="openModal2"> 选择人员 </a-button></div>--> |
| | | <Table></Table> |
| | |
| | | import {useModal} from "@/components/Modal"; |
| | | import {NewFollowUp} from "@/components/NewFollowUp"; |
| | | import {NewSchedule} from "@/components/NewSchedule"; |
| | | import {TagSelector} from "@/components/TagSelector/index"; |
| | | import PersonnelModal from "@/components/NewSchedule/src/PersonnelModal.vue"; |
| | | import ChangeStatusModal from "./components/change-status/index.vue"; |
| | | import ReallocateModal from "./components/reallocate/index.vue"; |
New file |
| | |
| | | <template> |
| | | <BasicDrawer |
| | | v-bind="$attrs" |
| | | title="Basic Drawer" |
| | | @register="registerDrawer" |
| | | :maskClosable="false" |
| | | :keyboard="false" |
| | | width="500px" |
| | | > |
| | | <template #title> |
| | | <div class="text-right"> |
| | | <span> |
| | | <Tooltip title="已关注"> |
| | | <Icon |
| | | icon="mingcute:heart-fill" |
| | | class="mr-15px cursor-pointer" |
| | | @click="" |
| | | :size="20" |
| | | /> |
| | | </Tooltip> |
| | | <Tooltip title="未关注"> |
| | | <Icon |
| | | icon="mingcute:heart-line" |
| | | class="mr-15px cursor-pointer" |
| | | @click="" |
| | | :size="20" |
| | | /> |
| | | </Tooltip> |
| | | </span> |
| | | <Icon |
| | | icon="ri:edit-line" |
| | | class="mr-15px cursor-pointer" |
| | | @click="" |
| | | :size="20" |
| | | /> |
| | | <Icon |
| | | icon="mdi:email-outline" |
| | | class="mr-15px cursor-pointer" |
| | | @click="" |
| | | :size="20" |
| | | /> |
| | | <Icon |
| | | icon="gg:add-r" |
| | | class="mr-15px cursor-pointer" |
| | | @click="" |
| | | :size="20" |
| | | /> |
| | | <a-dropdown :trigger="['click']"> |
| | | <Icon |
| | | icon="ri:more-2-fill" |
| | | class="cursor-pointer" |
| | | @click="" |
| | | :size="20" |
| | | /> |
| | | <template #overlay> |
| | | <a-menu> |
| | | <a-menu-item key="0"> |
| | | <span >转移</span> |
| | | </a-menu-item> |
| | | <a-menu-item key="1" @click="handleReallocate"> |
| | | <span>重新分配</span> |
| | | </a-menu-item> |
| | | <!-- <a-menu-divider />--> |
| | | <a-menu-item key="2">合并线索</a-menu-item> |
| | | <a-menu-item key="3">无效</a-menu-item> |
| | | <a-menu-item key="4">删除</a-menu-item> |
| | | </a-menu> |
| | | </template> |
| | | </a-dropdown> |
| | | </div> |
| | | |
| | | </template> |
| | | <Content></Content> |
| | | <!-- <BasicForm @register="registerForm"></BasicForm>--> |
| | | </BasicDrawer> |
| | | </template> |
| | | <script lang="ts" setup> |
| | | // import { useForm } from '@/components/Form'; |
| | | // import { formSchema } from './drawerData'; |
| | | import {BasicDrawer, useDrawerInner} from '@/components/Drawer'; |
| | | import Icon from "@/components/Icon/Icon.vue"; |
| | | import {Tooltip} from "ant-design-vue"; |
| | | import Content from "./drawer/index.vue"; |
| | | import EventBus from "@/utils/eventBus"; |
| | | import {reactive, defineEmits} from 'vue'; |
| | | |
| | | const emit = defineEmits(['success', 'register']); |
| | | |
| | | // const [registerForm, { setFieldsValue, }] = useForm({ |
| | | // labelWidth: 90, |
| | | // baseColProps: { span: 24 }, |
| | | // schemas: formSchema, |
| | | // showActionButtonGroup: false, |
| | | // }); |
| | | |
| | | // const [registerDrawer] = useDrawer(); |
| | | let currentClues = reactive({}); |
| | | const [registerDrawer] = useDrawerInner((data) => { |
| | | Logger.log('Drawer 注册回调', data); |
| | | currentClues = data.clue; |
| | | // // 方式1 |
| | | // setFieldsValue({ |
| | | // field2: data.data, |
| | | // field1: data.info, |
| | | // }); |
| | | }); |
| | | |
| | | function handleReallocate() { |
| | | Logger.log('点击了重新分配', currentClues); |
| | | EventBus.emit('openReallocateModal', currentClues); |
| | | } |
| | | |
| | | |
| | | </script> |
New file |
| | |
| | | <template> |
| | | <BasicDrawer |
| | | v-bind="$attrs" |
| | | title="新建客户" |
| | | @register="registerDrawer" |
| | | :maskClosable="false" |
| | | :keyboard="false" |
| | | width="860px" |
| | | showFooter |
| | | @ok="handleSubmit" |
| | | > |
| | | <template #title> |
| | | <div class="flex flex-justify-between"> |
| | | <div>{{ getTitle }}</div> |
| | | <div class="text-right"> |
| | | <span> |
| | | <Tooltip title="已关注"> |
| | | <Icon |
| | | icon="mingcute:heart-fill" |
| | | class="mr-15px cursor-pointer" |
| | | @click="" |
| | | :size="20" |
| | | /> |
| | | </Tooltip> |
| | | <Tooltip title="未关注"> |
| | | <Icon |
| | | icon="mingcute:heart-line" |
| | | class="mr-15px cursor-pointer" |
| | | @click="" |
| | | :size="20" |
| | | /> |
| | | </Tooltip> |
| | | </span> |
| | | |
| | | </div> |
| | | </div> |
| | | |
| | | </template> |
| | | <!-- <Content :schemas="schemas"></Content>--> |
| | | <div :class="prefixCls"> |
| | | <Alert |
| | | v-if="visible" |
| | | message="线索增强:填写公司网址或邮箱后缀后,如系统能查找到该公司的其他更多信息,则会为您自动补全。" |
| | | type="info" |
| | | show-icon |
| | | closable |
| | | :after-close="handleClose" |
| | | class="mb-10px" |
| | | /> |
| | | <Row :class="`${prefixCls}-top`"> |
| | | <Col :span="11" :class="`${prefixCls}-col`"> |
| | | <div class="mb-10px font-size-16px">常用信息</div> |
| | | <div class="pt-3px pr-3px"> |
| | | <BasicForm @register="registerForm" :model="modelRef" /> |
| | | </div> |
| | | </Col> |
| | | <Col :span="11" :offset="2" :class="`${prefixCls}-col`"> |
| | | <div class="mb-10px font-size-16px">联系人</div> |
| | | <div class="p-10px bg-gray-1"> |
| | | <BasicForm @register="registerForm2" /> |
| | | </div> |
| | | </Col> |
| | | </Row> |
| | | |
| | | </div> |
| | | </BasicDrawer> |
| | | </template> |
| | | <script lang="ts" setup> |
| | | // import { useForm } from '@/components/Form'; |
| | | // import { formSchema } from './drawerData'; |
| | | import {BasicDrawer, useDrawerInner} from '@/components/Drawer'; |
| | | import Icon from "@/components/Icon/Icon.vue"; |
| | | import {Alert, Col, Row, Tooltip} from "ant-design-vue"; |
| | | // import Content from "./drawer-form/index.vue"; |
| | | import {computed, ref, unref} from "vue"; |
| | | import {getMenuList} from "@/api/demo/system"; |
| | | import {TreeItem} from "@/components/Tree"; |
| | | import {BasicForm, useForm} from "@/components/Form"; |
| | | import {schemas} from './drawerFormData' |
| | | import {schemas as schemas2} from './drawerContacterFormData' |
| | | |
| | | const emit = defineEmits(['success', 'register']); |
| | | const isUpdate = ref(true); |
| | | const getTitle = computed(() => (!unref(isUpdate) ? '新建线索' : '编辑线索')); |
| | | |
| | | // const [registerForm, { setFieldsValue, }] = useForm({ |
| | | // labelWidth: 90, |
| | | // baseColProps: { span: 24 }, |
| | | // schemas: formSchema, |
| | | // showActionButtonGroup: false, |
| | | // }); |
| | | |
| | | // const [registerDrawer] = useDrawer(); |
| | | |
| | | const modelRef = ref({}); |
| | | // 左侧表单 |
| | | const [ |
| | | registerForm, |
| | | { resetFields, setFieldsValue, validate } |
| | | // { |
| | | // // setFieldsValue, |
| | | // // setProps |
| | | // }, |
| | | ] = useForm({ |
| | | layout: 'vertical', |
| | | // labelWidth: 100, |
| | | showAdvancedButton: true, //开启折叠 |
| | | autoAdvancedLine: 9, // 超过多少行折叠 |
| | | alwaysShowLines: 8, // 始终显示多少行 |
| | | schemas, |
| | | // showActionButtonGroup: false, // 默认显示操作按钮,开启才会显示折叠按钮 |
| | | showResetButton:false, // 隐藏重置按钮 |
| | | showSubmitButton:false, // 隐藏提交按钮 |
| | | actionColOptions: { |
| | | span: 24, |
| | | }, |
| | | }); |
| | | |
| | | // 右侧表单 |
| | | const [ |
| | | registerForm2, |
| | | { resetFields:resetFields2, setFieldsValue:setFieldsValue2, validate:validate2 } |
| | | // { |
| | | // // setFieldsValue, |
| | | // // setProps |
| | | // }, |
| | | ] = useForm({ |
| | | layout: 'vertical', |
| | | // labelWidth: 100, |
| | | showAdvancedButton: true, //开启折叠 |
| | | autoAdvancedLine: 5, // 超过多少行折叠 |
| | | alwaysShowLines: 4, // 始终显示多少行 |
| | | schemas:schemas2, |
| | | // showActionButtonGroup: false, // 默认显示操作按钮,开启才会显示折叠按钮 |
| | | showResetButton:false, // 隐藏重置按钮 |
| | | showSubmitButton:false, // 隐藏提交按钮 |
| | | actionColOptions: { |
| | | span: 24, |
| | | }, |
| | | }); |
| | | |
| | | |
| | | const [registerDrawer, { setDrawerProps, closeDrawer }] = useDrawerInner(async (data) => { |
| | | Logger.log('打开了DrawerForm', data); |
| | | isUpdate.value = !!data?.isUpdate; |
| | | // // 方式1 |
| | | // setFieldsValue({ |
| | | // field2: data.data, |
| | | // field1: data.info, |
| | | // }); |
| | | |
| | | // setDrawerProps({ confirmLoading: true }); |
| | | // setTimeout(() => { |
| | | // setDrawerProps({ confirmLoading: false }); |
| | | // }, 1000); |
| | | |
| | | resetFields(); |
| | | resetFields2(); |
| | | if (unref(isUpdate)) { |
| | | setFieldsValue({ |
| | | ...data.record, |
| | | }); |
| | | setFieldsValue2({ |
| | | ...data.record, |
| | | }); |
| | | } |
| | | }); |
| | | |
| | | |
| | | async function handleSubmit() { |
| | | try { |
| | | // const values = await validate(); |
| | | const [values, values2] = await Promise.all([validate(), validate2()]); |
| | | |
| | | // const values = getFieldsValue(); |
| | | Logger.log('点击submit 左侧表单values:',values); |
| | | Logger.log('点击submit 右侧表单values2:', values2); |
| | | setDrawerProps({ confirmLoading: true }); |
| | | // TODO custom api |
| | | |
| | | closeDrawer(); |
| | | emit('success'); |
| | | } finally { |
| | | setDrawerProps({ confirmLoading: false }); |
| | | } |
| | | } |
| | | |
| | | |
| | | |
| | | |
| | | const prefixCls = 'clues-drawer'; |
| | | // 关闭提示信息 |
| | | const visible = ref<boolean>(true); |
| | | const handleClose = () => { |
| | | visible.value = false; |
| | | }; |
| | | </script> |
| | |
| | | |
| | | const items = ref([ |
| | | { |
| | | key: '1', |
| | | label: 'Navigation One', |
| | | title: 'Navigation One', |
| | | key: '0', |
| | | label: '我的关注', |
| | | title: '我的关注', |
| | | }, |
| | | { |
| | | key: '2', |
| | | label: 'Navigation Two', |
| | | title: 'Navigation Two', |
| | | key: '1', |
| | | label: '全部客户', |
| | | title: '全部客户', |
| | | }, |
| | | { |
| | | key: 'sub1', |
| | | label: 'Navigation Three', |
| | | title: 'Navigation Three', |
| | | label: '分组', |
| | | title: '分组', |
| | | children: [ |
| | | { |
| | | key: '3', |
| | | label: 'Option 3', |
| | | title: 'Option 3', |
| | | label: '待处理', |
| | | title: '待处理', |
| | | }, |
| | | { |
| | | key: '4', |
| | | label: 'Option 4', |
| | | title: 'Option 4', |
| | | label: '完善信息', |
| | | title: '完善信息', |
| | | }, |
| | | { |
| | | key: 'sub1-2', |
| | | label: 'Submenu', |
| | | title: 'Submenu', |
| | | children: [ |
| | | { |
| | | key: '5', |
| | | label: 'Option 5', |
| | | title: 'Option 5', |
| | | }, |
| | | { |
| | | key: '6', |
| | | label: 'Option 6', |
| | | title: 'Option 6', |
| | | }, |
| | | ], |
| | | key: '5', |
| | | label: '初步触达', |
| | | title: '初步触达', |
| | | }, |
| | | |
| | | ], |
| | | }, |
| | | { |
| | | key: '2-1', |
| | | label: '近7天联系客户', |
| | | title: '近7天联系客户', |
| | | }, |
| | | { |
| | | key: '2-2', |
| | | label: '近7天收到新询盘', |
| | | title: '近7天收到新询盘', |
| | | }, |
| | | { |
| | | key: '2-3', |
| | | label: '7天内移入公海客户', |
| | | title: '7天内移入公海客户', |
| | | }, |
| | | { |
| | | key: 'sub2', |
| | | label: 'Navigation Four', |
| | | title: 'Navigation Four', |
| | | label: '客户阶段', |
| | | title: '客户阶段', |
| | | children: [ |
| | | { |
| | | key: '7', |
| | | label: 'Option 7', |
| | | title: 'Option 7', |
| | | label: '打开了营销', |
| | | title: '打开了营销', |
| | | }, |
| | | { |
| | | key: '8', |
| | | label: '回复了营销', |
| | | title: '回复了营销', |
| | | }, |
| | | { |
| | | key: '9', |
| | | label: '点击了链接', |
| | | title: '点击了链接', |
| | | }, |
| | | // { |
| | | // key: '10', |
| | | // label: 'Option 10', |
| | | // title: 'Option 10', |
| | | // }, |
| | | ], |
| | | }, |
| | | |
| | | { |
| | | key: 'sub3', |
| | | label: '国家地区(州)', |
| | | title: '线索来源', |
| | | children: [ |
| | | // { |
| | | // key: '7', |
| | | // label: '常规获客', |
| | | // title: '常规获客', |
| | | // }, |
| | | { |
| | | key: '7', |
| | | label: '常规获客', |
| | | title: '常规获客', |
| | | children: [ |
| | | |
| | | { |
| | | key: '6-1', |
| | | label: '全部', |
| | | title: '全部', |
| | | }, |
| | | { |
| | | key: '6-2', |
| | | label: '熟人介绍', |
| | | title: '熟人介绍', |
| | | }, |
| | | ], |
| | | }, |
| | | { |
| | | key: '8', |
| | |
| | | }, |
| | | ], |
| | | }, |
| | | { |
| | | key: '2', |
| | | label: '分组-1', |
| | | title: '分组-1', |
| | | children: [ |
| | | { |
| | | key: '3-1', |
| | | label: '待处理', |
| | | title: '待处理', |
| | | }, |
| | | { |
| | | key: '4-1', |
| | | label: '完善信息', |
| | | title: '完善信息', |
| | | }, |
| | | { |
| | | key: '5-1', |
| | | label: '初步触达', |
| | | title: '初步触达', |
| | | }, |
| | | |
| | | ], |
| | | }, |
| | | ]); |
| | | |
| | | const handleClick: MenuProps['onClick'] = e => { |
New file |
| | |
| | | <template> |
| | | <PageWrapper title="线索页"> |
| | | 666 |
| | | </PageWrapper> |
| | | </template> |
| | | <script lang="ts" setup> |
| | | import { PageWrapper } from '@/components/Page'; |
| | | |
| | | </script> |
| | |
| | | <template> |
| | | <div class="p-4 flex flex-col"> |
| | | <!-- <div class="mb-4">--> |
| | | <!-- <a-button class="mr-2" @click="reloadTable"> 还原 </a-button>--> |
| | | <!-- <a-button class="mr-2" @click="changeLoading"> 开启loading </a-button>--> |
| | | <!-- <a-button class="mr-2" @click="changeColumns"> 更改Columns </a-button>--> |
| | | <!-- <a-button class="mr-2" @click="getColumn"> 获取Columns </a-button>--> |
| | | <!-- <a-button class="mr-2" @click="getTableData"> 获取表格数据 </a-button>--> |
| | | <!-- <a-button class="mr-2" @click="getTableRawData"> 获取接口原始数据 </a-button>--> |
| | | <!-- <a-button class="mr-2" @click="setPaginationInfo"> 跳转到第2页 </a-button>--> |
| | | <!-- </div>--> |
| | | <!-- <div class="mb-4">--> |
| | | <!-- <a-button class="mr-2" @click="getSelectRowList"> 获取选中行 </a-button>--> |
| | | <!-- <a-button class="mr-2" @click="getSelectRowKeyList"> 获取选中行Key </a-button>--> |
| | | <!-- <a-button class="mr-2" @click="setSelectedRowKeyList"> 设置选中行 </a-button>--> |
| | | <!-- <a-button class="mr-2" @click="clearSelect"> 清空选中行 </a-button>--> |
| | | <!-- <a-button class="mr-2" @click="getPagination"> 获取分页信息 </a-button>--> |
| | | <!-- </div>--> |
| | | <Drawer @register="registerDrawer" @success="handleSuccess"/> |
| | | <!-- <div class="mb-4">--> |
| | | <!-- <a-button class="mr-2" @click="reloadTable"> 还原 </a-button>--> |
| | | <!-- <a-button class="mr-2" @click="changeLoading"> 开启loading </a-button>--> |
| | | <!--<!– <a-button class="mr-2" @click="changeColumns"> 更改Columns </a-button>–>--> |
| | | <!-- <a-button class="mr-2" @click="getColumn"> 获取Columns </a-button>--> |
| | | <!-- <a-button class="mr-2" @click="getTableData"> 获取表格数据 </a-button>--> |
| | | <!-- <a-button class="mr-2" @click="getTableRawData"> 获取接口原始数据 </a-button>--> |
| | | <!-- <a-button class="mr-2" @click="setPaginationInfo"> 跳转到第2页 </a-button>--> |
| | | <!-- </div>--> |
| | | <!-- <div class="mb-4">--> |
| | | <!-- <a-button class="mr-2" @click="getSelectRowList"> 获取选中行 </a-button>--> |
| | | <!-- <a-button class="mr-2" @click="getSelectRowKeyList"> 获取选中行Key </a-button>--> |
| | | <!-- <a-button class="mr-2" @click="setSelectedRowKeyList"> 设置选中行 </a-button>--> |
| | | <!-- <a-button class="mr-2" @click="clearSelect"> 清空选中行 </a-button>--> |
| | | <!-- <a-button class="mr-2" @click="getPagination"> 获取分页信息 </a-button>--> |
| | | <!-- </div>--> |
| | | <BasicTable |
| | | @register="registerTable" |
| | | @row-click="handleRowClick" |
| | |
| | | :beforeEditSubmit="beforeEditSubmit" |
| | | > |
| | | <template #bodyCell="{ column, record }"> |
| | | <template v-if="column.key === 'tags'" > |
| | | <template v-if="column.key === 'tags'"> |
| | | <div @click="handleCellClick"> |
| | | <span class="mr-1" v-for="tag in record.tags"> |
| | | <Tag |
| | |
| | | </Tag> |
| | | </span> |
| | | |
| | | <!-- <Dropdown--> |
| | | <!-- :dropMenuList="getDropMenuList"--> |
| | | <!-- :trigger="['click']"--> |
| | | <!-- placement="bottomCenter"--> |
| | | <!-- overlayClassName="multiple-tabs__dropdown"--> |
| | | <!-- >--> |
| | | <!-- <Icon icon="ion:chevron-down"/>--> |
| | | <!-- </Dropdown>--> |
| | | <!-- <Dropdown--> |
| | | <!-- :dropMenuList="getDropMenuList"--> |
| | | <!-- :trigger="['click']"--> |
| | | <!-- placement="bottomCenter"--> |
| | | <!-- overlayClassName="multiple-tabs__dropdown"--> |
| | | <!-- >--> |
| | | <!-- <Icon icon="ion:chevron-down"/>--> |
| | | <!-- </Dropdown>--> |
| | | </div> |
| | | </template> |
| | | <template v-else-if="column.key === 'action'"> |
| | | <TableAction |
| | | :actions="[ |
| | | { |
| | | label: '删除', |
| | | icon: 'ic:outline-delete-outline', |
| | | onClick: handleDelete.bind(null, record), |
| | | }, |
| | | ]" |
| | | stopButtonPropagation |
| | | :dropDownActions="[ |
| | | { |
| | | label: '启用', |
| | | popConfirm: { |
| | | title: '是否启用?', |
| | | confirm: handleOpen.bind(null, record), |
| | | }, |
| | | label: '转为客户', |
| | | onClick: handleConvertToCustomer.bind(null, record), |
| | | }, |
| | | { |
| | | label: '写邮件', |
| | | onClick: handleWriteEmail.bind(null, record), |
| | | }, |
| | | { |
| | | label: '写跟进', |
| | | onClick: handleWriteAFollowup.bind(null, record), |
| | | }, |
| | | { |
| | | label: '新建日程', |
| | | onClick: handleNewSchedule.bind(null, record), |
| | | }, |
| | | { |
| | | label: '变更状态', |
| | | onClick: handleChangeStatus.bind(null, record), |
| | | }, |
| | | { |
| | | label: '合并线索', |
| | | onClick: handleMergeClues.bind(null, record), |
| | | }, |
| | | { |
| | | label: '重新分配', |
| | | onClick: handleReallocate.bind(null, record), |
| | | }, |
| | | ]" |
| | | /> |
| | | </template> |
| | | </template> |
| | | <template #toolbar> |
| | | <a-button type="primary" @click="toggleCanResize"> |
| | | {{ !canResize ? '自适应高度' : '取消自适应' }} |
| | | </a-button> |
| | | <a-button type="primary" @click="toggleBorder"> |
| | | {{ !border ? '显示边框' : '隐藏边框' }} |
| | | </a-button> |
| | | <a-button type="primary" @click="toggleLoading"> 开启loading </a-button> |
| | | <a-button type="primary" @click="toggleStriped"> |
| | | {{ !striped ? '显示斑马纹' : '隐藏斑马纹' }} |
| | | </a-button> |
| | | </template> |
| | | </BasicTable> |
| | | </div> |
| | | </template> |
| | | <script lang="ts" setup> |
| | | import { ref,} from 'vue'; |
| | | import {ref,} from 'vue'; |
| | | import { |
| | | BasicTable, |
| | | ColumnChangeParam, |
| | | TableAction, |
| | | useTable |
| | | } from '@/components/Table'; |
| | | import {getBasicShortColumns, getEditCellColumns,getFormConfig} from './tableData'; |
| | | import { useMessage } from '@/hooks/web/useMessage'; |
| | | import { demoListApi } from '@/api/demo/table'; |
| | | import { Tag } from 'ant-design-vue'; |
| | | import {getEditCellColumns, getFormConfig} from './tableData'; |
| | | import {useMessage} from '@/hooks/web/useMessage'; |
| | | import {Tag} from 'ant-design-vue'; |
| | | import {cluesListApi} from "@/api/clues/table"; |
| | | // import {useModal} from "@/components/Modal"; |
| | | import Drawer from "./Drawer.vue"; |
| | | import {useDrawer} from "@/components/Drawer"; |
| | | import EventBus from "@/utils/eventBus"; |
| | | // import Icon from "@/components/Icon/Icon.vue"; |
| | | // import {Dropdown, type DropMenu} from "@/components/Dropdown"; |
| | | const { createMessage } = useMessage(); |
| | | // const [register, { openModal: openModal }] = useModal(); |
| | | // const [registerPersonnelModal, { openModal: openPersonnelModal }] = useModal(); |
| | | const [registerDrawer, {openDrawer}] = useDrawer(); |
| | | |
| | | const {createMessage} = useMessage(); |
| | | |
| | | function handleDelete(record: Recordable) { |
| | | console.log('点击了删除', record); |
| | | } |
| | | function handleOpen(record: Recordable) { |
| | | console.log('点击了启用', record); |
| | | |
| | | function handleConvertToCustomer(record: Recordable) { |
| | | Logger.log('点击了转为客户', record); |
| | | } |
| | | function handleWriteEmail(record: Recordable) { |
| | | Logger.log('点击了写邮件', record); |
| | | } |
| | | function handleWriteAFollowup(record: Recordable) { |
| | | Logger.log('点击了写跟进', record); |
| | | EventBus.emit('openFollowUpModal', record); |
| | | } |
| | | function handleNewSchedule(record: Recordable) { |
| | | Logger.log('点击了新建日程', record); |
| | | EventBus.emit('openScheduleModal', record); |
| | | } |
| | | function handleChangeStatus(record: Recordable) { |
| | | Logger.log('点击了变更状态', record); |
| | | EventBus.emit('openChangeStatusModal', record); |
| | | } |
| | | function handleMergeClues(record: Recordable) { |
| | | Logger.log('点击了合并线索', record); |
| | | } |
| | | function handleReallocate(record: Recordable) { |
| | | Logger.log('点击了重新分配', record); |
| | | EventBus.emit('openReallocateModal', record); |
| | | } |
| | | |
| | | const handleChange = (value: string) => { |
| | | console.log(`selected ${value}`); |
| | | }; |
| | | // const openModal = (value: string) => { |
| | | // console.log(`openModal ${value}`); |
| | | // }; |
| | | |
| | | |
| | | function handleSuccess() { |
| | | Logger.log('打开drawer成功'); |
| | | } |
| | | |
| | | |
| | | // const getDropMenuList = computed(() => { |
| | | // const dropMenuList: DropMenu[] = [ |
| | |
| | | function onChange() { |
| | | console.log('onChange', arguments); |
| | | } |
| | | |
| | | const [ |
| | | registerTable, |
| | | { |
| | |
| | | }, |
| | | ] = useTable({ |
| | | canResize: true, |
| | | title: 'useTable示例', |
| | | titleHelpMessage: '使用useTable调用表格内方法', |
| | | api: demoListApi, |
| | | // title: 'useTable示例', |
| | | // titleHelpMessage: '使用useTable调用表格内方法', |
| | | api: cluesListApi, |
| | | // beforeFetch: (params) => { |
| | | // console.log('beforeFetch', params); |
| | | // params.pageNo = params.page; |
| | | // // return Promise.resolve(params); |
| | | // }, |
| | | columns: getEditCellColumns(), |
| | | defSort: { |
| | | field: 'name', |
| | | order: 'ascend', |
| | | }, |
| | | // defSort: { |
| | | // pageNo: 1, |
| | | // pageSize: 20, |
| | | // field: 'name', |
| | | // order: 'ascend', |
| | | // }, |
| | | rowKey: 'id', |
| | | showTableSetting: true, |
| | | showIndexColumn: false, // 是否显示序号列 |
| | |
| | | // 是否显示全屏按钮 |
| | | fullScreen: true |
| | | }, |
| | | pagination: { |
| | | // pageSize: 20, |
| | | pageSizeOptions: ['10', '20', '50', '100'], |
| | | defaultPageSize: 20, |
| | | // showSizeChanger: true, |
| | | }, |
| | | onChange, |
| | | rowSelection: { |
| | | type: 'checkbox', |
| | |
| | | }, |
| | | showSelectionBar: true, // 显示多选状态栏 |
| | | actionColumn: { |
| | | width: 120, |
| | | width: 50, |
| | | title: '操作', |
| | | dataIndex: 'action', |
| | | fixed: 'right', |
| | |
| | | setLoading(false); |
| | | }, 1000); |
| | | } |
| | | function changeColumns() { |
| | | setProps({ |
| | | columns: getBasicShortColumns(), |
| | | rowSelection: { |
| | | type: 'checkbox', |
| | | }, |
| | | showIndexColumn: true, |
| | | }); |
| | | } |
| | | |
| | | // function changeColumns() { |
| | | // setProps({ |
| | | // columns: getBasicShortColumns(), |
| | | // rowSelection: { |
| | | // type: 'checkbox', |
| | | // }, |
| | | // showIndexColumn: true, |
| | | // }); |
| | | // } |
| | | function reloadTable() { |
| | | setProps({ |
| | | columns: getEditCellColumns(), |
| | |
| | | page: 1, |
| | | }); |
| | | } |
| | | |
| | | function getColumn() { |
| | | createMessage.info('请在控制台查看!'); |
| | | console.log(getColumns()); |
| | |
| | | }); |
| | | reload(); |
| | | } |
| | | |
| | | function getSelectRowList() { |
| | | createMessage.info('请在控制台查看!'); |
| | | console.log(getSelectRows()); |
| | | } |
| | | |
| | | function getSelectRowKeyList() { |
| | | createMessage.info('请在控制台查看!'); |
| | | console.log(getSelectRowKeys()); |
| | | } |
| | | |
| | | function setSelectedRowKeyList() { |
| | | setSelectedRowKeys(['0', '1', '2']); |
| | | } |
| | | |
| | | function clearSelect() { |
| | | clearSelectedRowKeys(); |
| | | } |
| | |
| | | const pagination = ref<any>(false); |
| | | |
| | | |
| | | |
| | | function toggleCanResize() { |
| | | canResize.value = !canResize.value; |
| | | } |
| | | function toggleStriped() { |
| | | striped.value = !striped.value; |
| | | } |
| | | function toggleLoading() { |
| | | loading.value = true; |
| | | setTimeout(() => { |
| | | loading.value = false; |
| | | pagination.value = { pageSize: 20 }; |
| | | }, 3000); |
| | | } |
| | | function toggleBorder() { |
| | | border.value = !border.value; |
| | | } |
| | | |
| | | |
| | | function handleEditEnd({ record, index, key, value }: Recordable) { |
| | | function handleEditEnd({record, index, key, value}: Recordable) { |
| | | console.log(record, index, key, value); |
| | | return false; |
| | | } |
| | | async function beforeEditSubmit({ record, index, key, value }) { |
| | | console.log('单元格数据正在准备提交', { record, index, key, value }); |
| | | return await feakSave({ id: record.id, key, value }); |
| | | |
| | | async function beforeEditSubmit({record, index, key, value}) { |
| | | console.log('单元格数据正在准备提交', {record, index, key, value}); |
| | | return await feakSave({id: record.id, key, value}); |
| | | } |
| | | |
| | | function handleEditCancel() { |
| | | console.log('cancel'); |
| | | } |
| | | function handleRowClick() { |
| | | console.log('handleRowClick'); |
| | | |
| | | function handleRowClick(data) { |
| | | Logger.log('handleRowClick', data); |
| | | openDrawer(true, { |
| | | isUpdate: false, |
| | | clue: data |
| | | }); |
| | | } |
| | | |
| | | function handleCellClick() { |
| | | console.log('handleCellClick..'); |
| | | } |
| | | |
| | | // 模拟将指定数据保存 |
| | | function feakSave({ value, key, id }) { |
| | | function feakSave({value, key, id}) { |
| | | createMessage.loading({ |
| | | content: `正在模拟保存${key}`, |
| | | key: '_save_fake_data', |
New file |
| | |
| | | <template> |
| | | <BasicModal |
| | | v-bind="$attrs" |
| | | @register="register" |
| | | title="变更状态" |
| | | @visible-change="handleVisibleChange" |
| | | @ok="handleSubmit" |
| | | > |
| | | <div class="mb-10px"> |
| | | 将线索【{{cluesName}}】状态变更为: |
| | | </div> |
| | | <div :class="'pt-3px pr-3px '+ prefixCls"> |
| | | <BasicForm @register="registerForm"></BasicForm> |
| | | </div> |
| | | |
| | | <div class="mt-10px c-gray"> |
| | | 注:如需切换线索状态为「已转化」,请使用"转为客户“功能 |
| | | </div> |
| | | </BasicModal> |
| | | </template> |
| | | <script lang="ts" setup> |
| | | import {ref, nextTick, h, unref} from 'vue'; |
| | | import {BasicModal, useModalInner} from '@/components/Modal'; |
| | | import {BasicForm, useForm} from '@/components/Form'; |
| | | |
| | | import {PlusOutlined, MinusOutlined,PaperClipOutlined} from '@ant-design/icons-vue'; |
| | | import {TreeSelect, Upload} from "ant-design-vue"; |
| | | import {optionsListApi} from "@/api/demo/select"; |
| | | const prefixCls = 'new-follow-up'; |
| | | const props = defineProps({ |
| | | userData: {type: Object}, |
| | | }); |
| | | const modelRef = ref({}); |
| | | const [registerForm,{validate:validate}] = useForm({ |
| | | schemas:[{ |
| | | field: 'cluesStatus', |
| | | component: 'ApiSelect', |
| | | label: '线索状态', |
| | | colProps: { |
| | | span: 24, |
| | | }, |
| | | required: true, |
| | | componentProps: { |
| | | api: optionsListApi, |
| | | params: { |
| | | id: 1, |
| | | }, |
| | | resultField: 'list', |
| | | // use name as label |
| | | labelField: 'name', |
| | | // use id as value |
| | | valueField: 'id', |
| | | // not request untill to select |
| | | immediate: true, |
| | | onChange: (e, v) => { |
| | | console.log('ApiSelect====>:', e, v); |
| | | }, |
| | | // atfer request callback |
| | | onOptionsChange: (options) => { |
| | | console.log('get options', options.length, options); |
| | | }, |
| | | }, |
| | | defaultValue: '1', |
| | | },], |
| | | showActionButtonGroup: false, |
| | | layout: 'vertical', |
| | | }); |
| | | |
| | | const [register,{ setModalProps, closeModal }] = useModalInner((data) => { |
| | | Logger.log('useModalInner data...', data); |
| | | data && onDataReceive(data); |
| | | setModalProps({ |
| | | // width: 800, |
| | | minHeight: 150, |
| | | canFullscreen: false, |
| | | destroyOnClose: true, |
| | | }); |
| | | }); |
| | | |
| | | |
| | | let cluesName = ref('测试1'); |
| | | function onDataReceive(data) { |
| | | console.log('Data Received', data); |
| | | cluesName.value = data.data.cluesName; |
| | | // 方式1; |
| | | // setFieldsValue({ |
| | | // field2: data.data, |
| | | // field1: data.info, |
| | | // }); |
| | | |
| | | // // 方式2 |
| | | modelRef.value = {field2: data.data, field1: data.info}; |
| | | |
| | | // setProps({ |
| | | // model:{ field2: data.data, field1: data.info } |
| | | // }) |
| | | } |
| | | |
| | | function handleVisibleChange(v) { |
| | | v && props.userData && nextTick(() => onDataReceive(props.userData)); |
| | | } |
| | | |
| | | // let currentFollowUpType = ref('1'); |
| | | // function handleFollowUpTypeChange(value: any) { |
| | | // Logger.log('handleFollowUpTypeChange...', value); |
| | | // } |
| | | |
| | | function removeFile(file: any) { |
| | | Logger.log('remove file...', file); |
| | | } |
| | | |
| | | async function handleSubmit() { |
| | | try { |
| | | const values = await validate(); |
| | | Logger.log('submit values', values); |
| | | setModalProps({ confirmLoading: true }); |
| | | // TODO custom api |
| | | // console.log(values); |
| | | closeModal(); |
| | | } finally { |
| | | setModalProps({ confirmLoading: false }); |
| | | } |
| | | } |
| | | </script> |
| | | |
| | | <style lang="less"> |
| | | |
| | | |
| | | </style> |
New file |
| | |
| | | |
| | | export default [ |
| | | { |
| | | label: '无采购额', |
| | | value: '1', |
| | | }, |
| | | { |
| | | label: '0~1千美元', |
| | | value: '2', |
| | | }, |
| | | { |
| | | label: '1千~5千美元', |
| | | value: '3', |
| | | }, |
| | | { |
| | | label: '5千~1万美元', |
| | | value: '4', |
| | | }, |
| | | { |
| | | label: '1万~3万美元', |
| | | value: '5', |
| | | }, |
| | | { |
| | | label: '3万~5万美元', |
| | | value: '6', |
| | | }, |
| | | { |
| | | label: '5万~10万美元', |
| | | value: '7', |
| | | },{ |
| | | label: '10万~30万美元', |
| | | value: '8', |
| | | }, |
| | | { |
| | | label: '30万~50万美元', |
| | | value: '9', |
| | | }, |
| | | { |
| | | label: '50万~100万美元', |
| | | value: '10', |
| | | }, |
| | | { |
| | | label: '100万~500万美元', |
| | | value: '11', |
| | | }, |
| | | { |
| | | label: '500万美元以上', |
| | | value: '12', |
| | | }, |
| | | |
| | | ] |
New file |
| | |
| | | export default [ |
| | | { |
| | | label: '原材料供应商', |
| | | value: '1', |
| | | }, |
| | | { |
| | | label: '生产商', |
| | | value: '2', |
| | | }, |
| | | { |
| | | label: '加盟商', |
| | | value: '3', |
| | | }, |
| | | { |
| | | label: '渠道商', |
| | | value: '4', |
| | | }, |
| | | { |
| | | label: '贸易商', |
| | | value: '5', |
| | | }, |
| | | { |
| | | label: '代理商', |
| | | value: '6', |
| | | }, |
| | | { |
| | | label: '批发商', |
| | | value: '7', |
| | | },{ |
| | | label: '零售商', |
| | | value: '8', |
| | | }, |
| | | { |
| | | label: '采购办事处', |
| | | value: '9', |
| | | }, |
| | | { |
| | | label: '采购咨询公司', |
| | | value: '10', |
| | | }, |
| | | { |
| | | label: '出口商', |
| | | value: '11', |
| | | }, |
| | | { |
| | | label: '进口商', |
| | | value: '12', |
| | | }, |
| | | { |
| | | label: '个人消费者', |
| | | value: '13', |
| | | }, |
| | | { |
| | | label: '机构/团体消费者', |
| | | value: '14', |
| | | }, |
| | | { |
| | | label: '工程商', |
| | | value: '15', |
| | | }, |
| | | { |
| | | label: '其他', |
| | | value: '16', |
| | | }, |
| | | |
| | | ] |
New file |
| | |
| | | <template> |
| | | <div :class="prefixCls"> |
| | | <Alert |
| | | v-if="visible" |
| | | message="线索增强:填写公司网址或邮箱后缀后,如系统能查找到该公司的其他更多信息,则会为您自动补全。" |
| | | type="info" |
| | | show-icon |
| | | closable |
| | | :after-close="handleClose" |
| | | class="mb-10px" |
| | | /> |
| | | <Row :class="`${prefixCls}-top`"> |
| | | <Col :span="11" :class="`${prefixCls}-col`"> |
| | | <div class="pt-3px pr-3px"> |
| | | <BasicForm @register="registerForm" :model="modelRef" /> |
| | | </div> |
| | | </Col> |
| | | <Col :span="11" :offset="2" :class="`${prefixCls}-col`"> |
| | | 5 |
| | | |
| | | </Col> |
| | | <!-- <Col :span="8" :class="`${prefixCls}-col`">--> |
| | | <!-- <CollapseContainer :class="`${prefixCls}-top__team`" title="团队" :canExpand="false">--> |
| | | <!-- <div v-for="(team, index) in teams" :key="index" :class="`${prefixCls}-top__team-item`">--> |
| | | <!-- <Icon :icon="team.icon" :color="team.color" />--> |
| | | <!-- <span>{{ team.title }}</span>--> |
| | | <!-- </div>--> |
| | | <!-- </CollapseContainer>--> |
| | | <!-- </Col>--> |
| | | </Row> |
| | | |
| | | </div> |
| | | </template> |
| | | |
| | | <script lang="ts" setup> |
| | | import Icon from '@/components/Icon/Icon.vue'; |
| | | import { Col, Row, Alert } from 'ant-design-vue'; |
| | | import {computed, unref, onMounted, type PropType} from 'vue'; |
| | | |
| | | import {BasicHelp} from "@/components/Basic"; |
| | | import { BasicForm, FormSchema, useForm } from '@/components/Form'; |
| | | const prefixCls = 'clues-drawer'; |
| | | |
| | | const visible = ref<boolean>(true); |
| | | const handleClose = () => { |
| | | visible.value = false; |
| | | }; |
| | | |
| | | import { ref } from 'vue'; |
| | | |
| | | import { defineProps } from 'vue' |
| | | const props = defineProps({ |
| | | schemas: { |
| | | type: Array as PropType<FormSchema[]>, |
| | | }, |
| | | }) |
| | | |
| | | |
| | | |
| | | const modelRef = ref({}); |
| | | const [ |
| | | registerForm, |
| | | // { |
| | | // // setFieldsValue, |
| | | // // setProps |
| | | // }, |
| | | ] = useForm({ |
| | | layout: 'vertical', |
| | | // labelWidth: 100, |
| | | schemas:props.schemas, |
| | | showActionButtonGroup: false, |
| | | actionColOptions: { |
| | | span: 24, |
| | | }, |
| | | }); |
| | | |
| | | onMounted(() => { |
| | | Logger.log('线索onMounted'); |
| | | }); |
| | | |
| | | |
| | | </script> |
| | | <style lang="less" scoped> |
| | | .clues-drawer { |
| | | &-col:not(:last-child) { |
| | | //padding: 0 10px; |
| | | |
| | | //&:not(:last-child) { |
| | | // border-right: 1px dashed rgb(206 206 206 / 50%); |
| | | //} |
| | | } |
| | | |
| | | } |
| | | </style> |
New file |
| | |
| | | export default [ |
| | | { |
| | | label: '零时区:伦敦', |
| | | value: '1', |
| | | }, |
| | | { |
| | | label: '东一区:罗马,巴黎', |
| | | value: '2', |
| | | }, |
| | | { |
| | | label: '东二区:雅典,以色列', |
| | | value: '3', |
| | | }, |
| | | { |
| | | label: '东三区:莫斯科,科威特', |
| | | value: '4', |
| | | }, |
| | | { |
| | | label: '东四区:喀布尔', |
| | | value: '5', |
| | | }, |
| | | { |
| | | label: '东五区:伊斯兰堡,卡拉奇', |
| | | value: '6', |
| | | }, |
| | | { |
| | | label: '东六区:阿拉木图,科伦坡', |
| | | value: '7', |
| | | },{ |
| | | label: '东七区:曼谷,雅加达', |
| | | value: '8', |
| | | }, |
| | | { |
| | | label: '东八区:北京,香港,台湾', |
| | | value: '9', |
| | | }, |
| | | { |
| | | label: '东九区:东京', |
| | | value: '10', |
| | | }, |
| | | { |
| | | label: '东十区:悉尼', |
| | | value: '11', |
| | | }, |
| | | { |
| | | label: '东十一区:霍尼亚拉,马加丹', |
| | | value: '12', |
| | | }, |
| | | { |
| | | label: '东西十二区:奥克兰', |
| | | value: '13', |
| | | }, |
| | | { |
| | | label: '西十一区:帕果帕果,阿洛菲', |
| | | value: '14', |
| | | }, |
| | | { |
| | | label: '西十区:夏威夷', |
| | | value: '15', |
| | | }, |
| | | { |
| | | label: '西九区:阿拉斯加', |
| | | value: '16', |
| | | }, |
| | | { |
| | | label: '西八区:洛杉矶,旧金山', |
| | | value: '17', |
| | | }, |
| | | { |
| | | label: '西七区:盐湖城、丹佛、凤凰城', |
| | | value: '18', |
| | | }, |
| | | { |
| | | label: '西六区:芝加哥,休斯顿,亚特兰大', |
| | | value: '19', |
| | | }, |
| | | { |
| | | label: '西五区:纽约,华盛顿,波士顿', |
| | | value: '20', |
| | | }, |
| | | { |
| | | label: '西四区:加拿大,加拉加斯', |
| | | value: '21', |
| | | }, |
| | | { |
| | | label: '西三区:巴西利亚', |
| | | value: '22', |
| | | }, |
| | | { |
| | | label: '西二区:协调世界时', |
| | | value: '23', |
| | | }, |
| | | { |
| | | label: '西一区:佛得角群岛', |
| | | value: '24', |
| | | }, |
| | | |
| | | ] |
New file |
| | |
| | | <template> |
| | | <Row class="mb-10px"> |
| | | <Col span="12"> |
| | | <Dropdown :trigger="['click']" arrow @openChange="openChange"> |
| | | <span class="cursor-pointer" @click.prevent> |
| | | {{ dropDownTitle }} |
| | | <BasicArrow :expand="false" down/> |
| | | </span> |
| | | <template #overlay> |
| | | <Menu @click="onMenuItemClick"> |
| | | <MenuItem key="0"> |
| | | <span>未完成</span> |
| | | </MenuItem> |
| | | <MenuItem key="1"> |
| | | <span>已完成</span> |
| | | </MenuItem> |
| | | </Menu> |
| | | </template> |
| | | </Dropdown> |
| | | </Col> |
| | | <Col span="12" :style="'text-align:right'"> |
| | | <Tooltip title="新建日程"> |
| | | <PlusSquareOutlined class="cursor-pointer" style="fontSize:24px;color: #aaa" |
| | | @click="openScheduleModal"/> |
| | | </Tooltip> |
| | | |
| | | </Col> |
| | | </Row> |
| | | <BasicTable |
| | | @register="registerTable" |
| | | @row-click="handleScheduleRowClick" |
| | | > |
| | | <template #bodyCell="{ column, record }"> |
| | | <template v-if="column.key === 'cluesName'"> |
| | | <div> |
| | | <Avatar :size="16" :style="'background-color:'+ record.color"></Avatar> |
| | | <span class="ml-5px"> |
| | | {{ record.cluesName }} |
| | | </span> |
| | | </div> |
| | | </template> |
| | | </template> |
| | | </BasicTable> |
| | | <ScheduleDetailModal @register="registerScheduleModal"></ScheduleDetailModal> |
| | | <div> |
| | | <template v-for="item in projectList" :key="item.title"> |
| | | <Row class="cursor-pointer" :gutter="[22,26]" align="middle"> |
| | | <Col span="12"> |
| | | <Avatar :size="16" :style="'background-color:'+ item.color"></Avatar> |
| | | <span class="ml-5px">{{ item.title }}</span> |
| | | </Col> |
| | | <Col span="12" :style="'text-align:right'"> |
| | | <span>{{ item.content }}</span> |
| | | </Col> |
| | | </Row> |
| | | </template> |
| | | |
| | | </div> |
| | | <!-- <List :class="prefixCls" item-layout="horizontal" :data-source="projectList" :grid="{ column: 1, gutter: 12}" :pagination="pagination" >--> |
| | | <!-- <template #renderItem="{ item }">--> |
| | | <!-- <ListItem>--> |
| | | <!-- --> |
| | | <!-- </ListItem>--> |
| | | |
| | | <!-- </template>--> |
| | | <!--<!– <template v-for="item in projectList" :key="item.title"></template>–>--> |
| | | <!-- </List>--> |
| | | </template> |
| | | <script lang="ts" setup> |
| | | import {List, Avatar, Card, Row, Col, Dropdown, Menu, Tooltip, Tag} from 'ant-design-vue'; |
| | | import {projectList} from './data'; |
| | | import {PlusSquareOutlined} from '@ant-design/icons-vue'; |
| | | import {BasicArrow} from "@/components/Basic"; |
| | | import {ref} from 'vue'; |
| | | import ScheduleDetailModal from './ScheduleDetail.vue'; |
| | | |
| | | const ListItem = List.Item; |
| | | const MenuItem = Menu.Item; |
| | | |
| | | import EventBus from '@/utils/eventBus'; |
| | | import {BasicTable, ColumnChangeParam, TableAction, useTable} from "@/components/Table"; |
| | | import {cluesListApi} from "@/api/clues/table"; |
| | | import {getEditCellColumns, getFormConfig} from "@/views/clues/components/tableData"; |
| | | import {useModal} from "@/components/Modal"; |
| | | |
| | | const [registerScheduleModal, {openModal, setModalProps}] = useModal(); |
| | | const openScheduleModal = () => { |
| | | Logger.log('点击openScheduleModal'); |
| | | EventBus.emit('openScheduleModal', { |
| | | title: '新建任务', |
| | | content: '新建任务内容' |
| | | }); |
| | | }; |
| | | |
| | | const pagination = { |
| | | onChange: (page: number) => { |
| | | console.log(page); |
| | | }, |
| | | pageSize: 3, |
| | | }; |
| | | |
| | | const openChange = (status: boolean) => { |
| | | Logger.log('openChange', status); |
| | | }; |
| | | const dropDownTitle = ref('未完成'); |
| | | const onMenuItemClick = (e: any) => { |
| | | let titles = ['未完成', '已完成']; |
| | | Logger.log('onMenuItemClick', e); |
| | | dropDownTitle.value = titles[e.key]; |
| | | }; |
| | | |
| | | const [ |
| | | registerTable, |
| | | { |
| | | // setLoading, |
| | | // setProps, |
| | | // getColumns, |
| | | // getDataSource, |
| | | // getRawDataSource, |
| | | // reload, |
| | | // getPaginationRef, |
| | | // setPagination, |
| | | // getSelectRows, |
| | | // getSelectRowKeys, |
| | | // setSelectedRowKeys, |
| | | // clearSelectedRowKeys, |
| | | }, |
| | | ] = useTable({ |
| | | canResize: true, |
| | | api: cluesListApi, |
| | | // beforeFetch: (params) => { |
| | | // console.log('beforeFetch', params); |
| | | // params.pageNo = params.page; |
| | | // // return Promise.resolve(params); |
| | | // }, |
| | | showIndexColumn: false, |
| | | columns: [ |
| | | { |
| | | // title: '', |
| | | // defaultHidden: true, |
| | | dataIndex: 'cluesName', |
| | | width: 200 |
| | | }, |
| | | { |
| | | // title: '', |
| | | dataIndex: 'archiveTime', |
| | | width: 200, |
| | | }, |
| | | ], |
| | | // defSort: { |
| | | // pageNo: 1, |
| | | // pageSize: 20, |
| | | // field: 'name', |
| | | // order: 'ascend', |
| | | // }, |
| | | rowKey: 'id', |
| | | // showTableSetting: false, |
| | | // showIndexColumn: false, // 是否显示序号列 |
| | | // useSearchForm: false, // 使用搜索表单 |
| | | // clickToRowSelect: false, |
| | | // formConfig: getFormConfig(), // 搜索表单配置 |
| | | pagination: { |
| | | // pageSize: 20, |
| | | pageSizeOptions: ['10', '20', '50', '100'], |
| | | defaultPageSize: 20, |
| | | // showSizeChanger: true, |
| | | }, |
| | | }); |
| | | |
| | | |
| | | |
| | | function handleScheduleRowClick(e) { |
| | | Logger.log('handleScheduleRowClick', e); |
| | | openModal(true, { |
| | | // record, |
| | | // isUpdate: true, |
| | | }); |
| | | } |
| | | |
| | | const prefixCls = 'account-center-project'; |
| | | </script> |
| | | <style lang="less" > |
| | | |
| | | </style> |
New file |
| | |
| | | <template> |
| | | <div :class="prefixCls"> |
| | | <BasicForm @register="registerForm"></BasicForm> |
| | | <div class="mb-15px"> |
| | | <div class="mb-15px "> |
| | | <div :class="`${prefixCls}__label`">系统标签</div> |
| | | <div>暂无数据</div> |
| | | </div> |
| | | <div class="mb-15px"> |
| | | <div :class="`${prefixCls}__label`">首次跟进时间</div> |
| | | <div>暂无数据</div> |
| | | </div> |
| | | <div class=""> |
| | | <div :class="`${prefixCls}__label`">未联系天数</div> |
| | | <div>10</div> |
| | | </div> |
| | | </div> |
| | | <Divider /> |
| | | <h3>公司信息</h3> |
| | | <Description @register="register" class="mt-4" /> |
| | | <Divider /> |
| | | <h3>联系人</h3> |
| | | <Description @register="register" class="mt-4" /> |
| | | <Divider /> |
| | | <h3>系统信息</h3> |
| | | <Description @register="register" class="mt-4" /> |
| | | </div> |
| | | </template> |
| | | <script lang="ts" setup> |
| | | import { List, Tag, Divider } from 'ant-design-vue'; |
| | | import Icon from '@/components/Icon/Icon.vue'; |
| | | import {BasicForm, FormSchema, useForm} from '@/components/Form'; |
| | | import dayjs from "dayjs"; |
| | | import {treeOptionsListApi} from "@/api/demo/tree"; |
| | | import {getAllRoleList} from "@/api/demo/system"; |
| | | import {DescItem, Description, useDescription} from "@/components/Description"; |
| | | |
| | | const formSchema: FormSchema[] = [ |
| | | { |
| | | field: 'field33', |
| | | component: 'ApiTreeSelect', |
| | | label: '线索来源', |
| | | // helpMessage: ['ApiTreeSelect组件', '使用接口提供的数据生成选项'], |
| | | required: true, |
| | | componentProps: { |
| | | api: treeOptionsListApi, |
| | | treeCheckable: true, |
| | | resultField: 'list', |
| | | onChange: (e, v) => { |
| | | console.log('ApiTreeSelect====>:', e, v); |
| | | }, |
| | | }, |
| | | colProps: { |
| | | span: 24, |
| | | }, |
| | | }, |
| | | { |
| | | component: 'Select', |
| | | label: '线索状态', |
| | | field: 'date1', |
| | | colProps: { span: 24 }, |
| | | componentProps: { |
| | | options: [ |
| | | { |
| | | label: '待处理', |
| | | value: '1', |
| | | }, |
| | | { |
| | | label: '完善信息', |
| | | value: '2', |
| | | }, |
| | | { |
| | | label: '初步触达', |
| | | value: '3', |
| | | }, |
| | | { |
| | | label: '联系互动', |
| | | value: '4', |
| | | }, |
| | | ], |
| | | }, |
| | | defaultValue:'1' |
| | | }, |
| | | { |
| | | label: '国家地区', |
| | | field: 'country', |
| | | component: 'ApiSelect', |
| | | componentProps: { |
| | | api: getAllRoleList, |
| | | labelField: 'roleName', |
| | | valueField: 'roleValue', |
| | | }, |
| | | }, |
| | | { |
| | | label: '线索备注', |
| | | field: 'field0', |
| | | component: 'InputTextArea', |
| | | componentProps:{ |
| | | placeholder: '请输入备注内容', |
| | | }, |
| | | colProps: { |
| | | span: 24, |
| | | }, |
| | | }, |
| | | ]; |
| | | |
| | | const mockData: Recordable = { |
| | | cluesName: 'test', |
| | | nickName: 'VB', |
| | | age: '123', |
| | | phone: '15695909xxx', |
| | | email: '190848757@qq.com', |
| | | companyname: '公司名称111', |
| | | sex: '男', |
| | | certy: '3504256199xxxxxxxxx', |
| | | tag: 'orange', |
| | | }; |
| | | |
| | | const schema: DescItem[] = [ |
| | | { |
| | | field: 'cluesName', |
| | | label: '线索名称', |
| | | }, |
| | | |
| | | { |
| | | field: 'companyname', |
| | | label: '公司名称', |
| | | }, |
| | | { |
| | | field: 'phone', |
| | | label: '联系电话', |
| | | }, |
| | | { |
| | | field: 'email', |
| | | label: '邮箱', |
| | | }, |
| | | { |
| | | field: 'phone', |
| | | label: '座机', |
| | | render: (curVal, data) => { |
| | | return `${data.nickName}-${curVal}`; |
| | | }, |
| | | }, |
| | | ]; |
| | | |
| | | const [registerForm] = useForm({ |
| | | layout: 'vertical', |
| | | baseColProps: { span: 24 }, |
| | | schemas: formSchema, |
| | | showActionButtonGroup: false, |
| | | }); |
| | | |
| | | const [register] = useDescription({ |
| | | // title: '无边框', |
| | | layout: 'vertical', |
| | | bordered: false, |
| | | column: 1, |
| | | labelStyle:{ |
| | | color: '#909090', |
| | | // fontSize: '12px', |
| | | }, |
| | | data: mockData, |
| | | schema: schema, |
| | | }); |
| | | |
| | | const prefixCls = 'clues-tab-detail'; |
| | | </script> |
| | | <style lang="less" scoped> |
| | | .clues-tab-detail { |
| | | background-color: @component-background; |
| | | &__title { |
| | | margin-bottom: 12px; |
| | | font-size: 18px; |
| | | } |
| | | |
| | | &__content { |
| | | color: @text-color-secondary; |
| | | } |
| | | |
| | | &__label { |
| | | color: @text-color-secondary; |
| | | } |
| | | |
| | | &__action { |
| | | display: inline-block; |
| | | padding: 0 16px; |
| | | color: @text-color-secondary; |
| | | |
| | | &:nth-child(1), |
| | | &:nth-child(2) { |
| | | border-right: 1px solid rgb(206 206 206 / 40%); |
| | | } |
| | | |
| | | &-icon { |
| | | margin-right: 3px; |
| | | } |
| | | } |
| | | |
| | | &__time { |
| | | position: absolute; |
| | | right: 20px; |
| | | color: rgb(0 0 0 / 45%); |
| | | } |
| | | } |
| | | </style> |
New file |
| | |
| | | <template> |
| | | <a-collapse v-model:activeKey="activeKey" ghost> |
| | | <a-collapse-panel key="1" header="文档"> |
| | | <BasicTable |
| | | @register="registerTable" |
| | | @row-click="handleScheduleRowClick" |
| | | > |
| | | <template #bodyCell="{ column, record }"> |
| | | <template v-if="column.key === 'cluesName'"> |
| | | <div> |
| | | <a-avatar :size="16" :style="'background-color:'+ record.color"></a-avatar> |
| | | <span class="ml-5px"> |
| | | {{ record.cluesName }} |
| | | </span> |
| | | </div> |
| | | </template> |
| | | </template> |
| | | </BasicTable> |
| | | </a-collapse-panel> |
| | | </a-collapse> |
| | | |
| | | <ScheduleDetailModal @register="registerScheduleModal"></ScheduleDetailModal> |
| | | |
| | | </template> |
| | | <script lang="ts" setup> |
| | | import {projectList} from './data'; |
| | | import {PlusSquareOutlined} from '@ant-design/icons-vue'; |
| | | import {BasicArrow} from "@/components/Basic"; |
| | | import {ref} from 'vue'; |
| | | import ScheduleDetailModal from './ScheduleDetail.vue'; |
| | | |
| | | import EventBus from '@/utils/eventBus'; |
| | | import {BasicTable, ColumnChangeParam, TableAction, useTable} from "@/components/Table"; |
| | | import {cluesListApi} from "@/api/clues/table"; |
| | | import {getEditCellColumns, getFormConfig} from "@/views/clues/components/tableData"; |
| | | import {useModal} from "@/components/Modal"; |
| | | |
| | | const [registerScheduleModal, {openModal, setModalProps}] = useModal(); |
| | | const openScheduleModal = () => { |
| | | Logger.log('点击openScheduleModal'); |
| | | EventBus.emit('openScheduleModal', { |
| | | title: '新建任务', |
| | | content: '新建任务内容' |
| | | }); |
| | | }; |
| | | |
| | | const activeKey = ref(['1']); |
| | | |
| | | const pagination = { |
| | | onChange: (page: number) => { |
| | | console.log(page); |
| | | }, |
| | | pageSize: 3, |
| | | }; |
| | | |
| | | const openChange = (status: boolean) => { |
| | | Logger.log('openChange', status); |
| | | }; |
| | | const dropDownTitle = ref('未完成'); |
| | | const onMenuItemClick = (e: any) => { |
| | | let titles = ['未完成', '已完成']; |
| | | Logger.log('onMenuItemClick', e); |
| | | dropDownTitle.value = titles[e.key]; |
| | | }; |
| | | |
| | | const [ |
| | | registerTable, |
| | | { |
| | | // setLoading, |
| | | // setProps, |
| | | // getColumns, |
| | | // getDataSource, |
| | | // getRawDataSource, |
| | | // reload, |
| | | // getPaginationRef, |
| | | // setPagination, |
| | | // getSelectRows, |
| | | // getSelectRowKeys, |
| | | // setSelectedRowKeys, |
| | | // clearSelectedRowKeys, |
| | | }, |
| | | ] = useTable({ |
| | | canResize: true, |
| | | api: cluesListApi, |
| | | // beforeFetch: (params) => { |
| | | // console.log('beforeFetch', params); |
| | | // params.pageNo = params.page; |
| | | // // return Promise.resolve(params); |
| | | // }, |
| | | showIndexColumn: false, |
| | | columns: [ |
| | | { |
| | | // title: '', |
| | | // defaultHidden: true, |
| | | dataIndex: 'cluesName', |
| | | width: 200 |
| | | }, |
| | | { |
| | | // title: '', |
| | | dataIndex: 'archiveTime', |
| | | width: 200, |
| | | }, |
| | | ], |
| | | // defSort: { |
| | | // pageNo: 1, |
| | | // pageSize: 20, |
| | | // field: 'name', |
| | | // order: 'ascend', |
| | | // }, |
| | | rowKey: 'id', |
| | | // showTableSetting: false, |
| | | // showIndexColumn: false, // 是否显示序号列 |
| | | // useSearchForm: false, // 使用搜索表单 |
| | | // clickToRowSelect: false, |
| | | // formConfig: getFormConfig(), // 搜索表单配置 |
| | | pagination: { |
| | | // pageSize: 20, |
| | | pageSizeOptions: ['10', '20', '50', '100'], |
| | | defaultPageSize: 20, |
| | | // showSizeChanger: true, |
| | | }, |
| | | }); |
| | | |
| | | |
| | | |
| | | function handleScheduleRowClick(e) { |
| | | Logger.log('handleScheduleRowClick', e); |
| | | openModal(true, { |
| | | // record, |
| | | // isUpdate: true, |
| | | }); |
| | | } |
| | | |
| | | const prefixCls = 'account-center-project'; |
| | | </script> |
| | | <style lang="less" > |
| | | |
| | | </style> |
New file |
| | |
| | | <template> |
| | | <div :class="prefixCls" > |
| | | <div class="mb-20px"> |
| | | <a-button type="primary" shape="round" block @click="openFollowUpModal"> |
| | | <template #icon> |
| | | <PlusCircleOutlined /> |
| | | </template> |
| | | 添加跟进 |
| | | </a-button> |
| | | </div> |
| | | <div ref="wrapEl"> |
| | | <div class="mb-20px flex justify-between flex-items-center"> |
| | | <span class="font-bold">共 {{totalData}} 条</span> |
| | | <TreeSelect |
| | | v-model:value="currentDynamicType" |
| | | :dropdownStyle="{color: 'red'}" |
| | | style="width: 120px" |
| | | placeholder="Please select" |
| | | :allow-clear="false" |
| | | :bordered="false" |
| | | tree-default-expand-all |
| | | :tree-data="dynamicTypeTree" |
| | | @change="handleDynamicTypeChange" |
| | | > |
| | | </TreeSelect> |
| | | </div> |
| | | <Timeline > |
| | | <TimelineItem v-for="item in dynamicList" :key="item.id"> |
| | | <Row> |
| | | <Col span="16" class="c-gray-4"> |
| | | {{item.cluesName}} |
| | | </Col> |
| | | <Col :offset="2" span="6" class="c-gray-4"> |
| | | {{item.privateTime}} |
| | | </Col> |
| | | </Row> |
| | | <div> |
| | | {{item.failStatusName}} |
| | | </div> |
| | | <div> |
| | | <ImagePreviewGroup> |
| | | <template v-for="(img,index) in item.imageList" :key="index"> |
| | | <Image :width="100" class="pr-10px" :src="img" /> |
| | | </template> |
| | | </ImagePreviewGroup> |
| | | </div> |
| | | </TimelineItem> |
| | | </Timeline> |
| | | </div> |
| | | |
| | | <!-- show-size-changer--> |
| | | <!-- show-quick-jumper--> |
| | | <!-- :show-total="total => `共 ${total} 条数据`"--> |
| | | <Pagination |
| | | class="text-right" |
| | | v-model:current="currentPage" |
| | | v-model:page-size="pageSize" |
| | | :total="totalData" |
| | | responsive |
| | | show-less-items |
| | | :pageSizeOptions="['10','20', '30', '50']" |
| | | @change="handlePageChange" |
| | | /> |
| | | </div> |
| | | </template> |
| | | <script lang="ts" setup> |
| | | import { Timeline,Row,Col,ImagePreviewGroup,Image,Pagination,TreeSelect } from 'ant-design-vue'; |
| | | import Icon from '@/components/Icon/Icon.vue'; |
| | | import { applicationList } from './data'; |
| | | import {cluesDynamicApi} from "@/api/clues/dynamic"; |
| | | import {ref,unref,getCurrentInstance} from "vue"; |
| | | import {useLoading} from "@/components/Loading"; |
| | | import {PlusCircleOutlined} from "@ant-design/icons-vue"; |
| | | import {treeOptionsListApi} from "@/api/demo/tree"; |
| | | import EventBus from "@/utils/eventBus"; |
| | | const TimelineItem = Timeline.Item; |
| | | |
| | | const prefixCls = 'clues-tab-dynamic'; |
| | | |
| | | let dynamicList = ref([] as any[]); |
| | | let totalData = ref(0); |
| | | |
| | | let currentPage = ref(1); |
| | | let pageSize = ref(10); |
| | | |
| | | const handlePageChange = (current: number, size: number) => { |
| | | currentPage.value = current; |
| | | pageSize.value = size; |
| | | // console.log('PageChange',currentPage, pageSize); |
| | | getCluesDynamicData(); |
| | | }; |
| | | |
| | | // 打开跟进弹窗 |
| | | const openFollowUpModal = () => { |
| | | Logger.log('openFollowUpModal...'); |
| | | EventBus.emit('openFollowUpModal', { |
| | | title: '新建任务', |
| | | content: '新建任务内容' |
| | | }); |
| | | }; |
| | | // let _this = getCurrentInstance(); |
| | | |
| | | // 动态类型treeData |
| | | let currentDynamicType = ref('0-0'); |
| | | let dynamicTypeTree = ref([]); |
| | | getTreeData(); |
| | | async function getTreeData() { |
| | | try { |
| | | const data = await treeOptionsListApi(); |
| | | dynamicTypeTree.value = data?.list || []; |
| | | Logger.log('treeOptionsListApi...dynamicTypeTree', dynamicTypeTree); |
| | | } catch (e) { |
| | | Logger.error(e); |
| | | } finally { |
| | | |
| | | } |
| | | } |
| | | function handleDynamicTypeChange(value: any) { |
| | | Logger.log('handleDynamicTypeChange...', value); |
| | | } |
| | | |
| | | // 动态列表加载 |
| | | const wrapEl = ref<ElRef>(null); |
| | | const [openWrapLoading, closeWrapLoading] = useLoading({ |
| | | target: wrapEl, |
| | | props: { |
| | | tip: '加载中...', |
| | | absolute: true, |
| | | }, |
| | | }); |
| | | // 动态列表数据 |
| | | getCluesDynamicData(); |
| | | async function getCluesDynamicData(){ |
| | | openWrapLoading(); |
| | | let params = { |
| | | page: currentPage.value, |
| | | pageSize: pageSize.value, |
| | | }; |
| | | try { |
| | | // cluesDynamicApi(params).then(res => { |
| | | // |
| | | // }) |
| | | let res = await cluesDynamicApi(params) |
| | | Logger.log('cluesDynamicApi...',res); |
| | | // console.log(_this); |
| | | // _this.$set(dynamicList,res.items) |
| | | dynamicList.value = res.items; |
| | | totalData.value = res.total; |
| | | |
| | | } catch (e) { |
| | | Logger.error(e); |
| | | } finally { |
| | | closeWrapLoading(); |
| | | } |
| | | } |
| | | </script> |
| | | <style lang="less"> |
| | | .clues-tab-dynamic { |
| | | .ant-select-arrow{ |
| | | color: #000; |
| | | } |
| | | } |
| | | </style> |
New file |
| | |
| | | <template> |
| | | <BasicModal |
| | | v-bind="$attrs" |
| | | @register="register" |
| | | @visible-change="handleVisibleChange" |
| | | class="schedule-detail-modal" |
| | | > |
| | | <template #title></template> |
| | | <template #closeIcon></template> |
| | | <Tabs v-model:activeKey="activeKey" @change="onTabsChange"> |
| | | <TabPane key="1" tab="详情"> |
| | | <div> |
| | | <div> |
| | | <Row class="mb-10px"> |
| | | <Col span="12" class="font-bold">2024-09</Col> |
| | | <Col span="12" class="c-gray text-right"> |
| | | <ClockCircleOutlined /> |
| | | 2024-09-09 09:00:00 |
| | | </Col> |
| | | </Row> |
| | | <Row> |
| | | <Col span="20" class=""> |
| | | <Checkbox v-model:checked="checked"> |
| | | <Avatar class="align-inherit" :size="10" :style="'background-color:'+ '#ddd'"></Avatar> |
| | | <span class="pl-10px">测试1</span> |
| | | </Checkbox> |
| | | <Row class="c-gray ml-22px">今天</Row> |
| | | </Col> |
| | | <Col span="4" class="font-bold text-right"> |
| | | <HeartOutlined class="font-size-18px" /> |
| | | <HeartFilled class="font-size-18px c-red-5" /> |
| | | </Col> |
| | | </Row> |
| | | </div> |
| | | <Divider /> |
| | | <div> |
| | | <div class="mb-10px"> |
| | | <div class="c-gray">关联线索:</div> |
| | | <a href="javascript:void(0)">测试1</a> |
| | | </div> |
| | | <div class="mb-10px"> |
| | | <div class="c-gray">参与人:</div> |
| | | <span >测试1</span> |
| | | </div> |
| | | <div class="mb-10px"> |
| | | <div class="c-gray">创建人:</div> |
| | | <span >测试1</span> |
| | | </div> |
| | | |
| | | </div> |
| | | <Divider /> |
| | | |
| | | </div> |
| | | </TabPane> |
| | | <TabPane key="2" tab="评论"> |
| | | <div class="mb-10px scroll-wrap"> |
| | | <ScrollContainer class=""> |
| | | <Empty></Empty> |
| | | <div> |
| | | <Row> |
| | | <Col span="12" class="font-size-18px"> |
| | | Tuku |
| | | </Col> |
| | | <Col span="12" class="text-right"> |
| | | <span class="c-gray pr-10px">2024-09-09 09:00:00</span> |
| | | <EditOutlined class="font-size-18px cursor-pointer c-blue-5 mr-10px"/> |
| | | <CloseOutlined class="font-size-18px cursor-pointer c-red-5"/> |
| | | </Col> |
| | | </Row> |
| | | <Row> |
| | | <Col span="24">测试评论2</Col> |
| | | </Row> |
| | | <!-- <Flex >--> |
| | | <!-- <div--> |
| | | <!-- v-for="(item, index) in new Array(4)"--> |
| | | <!-- :key="item"--> |
| | | <!-- :style="{ ...baseStyle, background: `${index % 2 ? '#1677ff' : '#1677ffbf'}` }"--> |
| | | <!-- />--> |
| | | <!-- </Flex>--> |
| | | <ImagePreviewGroup> |
| | | <Image :width="120" src="https://aliyuncdn.antdv.com/vue.png"></Image> |
| | | </ImagePreviewGroup> |
| | | <Upload |
| | | v-model:file-list="fileList" |
| | | action="https://www.mocky.io/v2/5cc8019d300000980a055e76" |
| | | list-type="picture" |
| | | @remove="removeFile" |
| | | class="upload-list-inline" |
| | | :showUploadList="{ showDownloadIcon: true,showRemoveIcon: false }" |
| | | > |
| | | |
| | | </Upload> |
| | | </div> |
| | | </ScrollContainer> |
| | | </div> |
| | | <div class="scroll-wrap"> |
| | | <Divider /> |
| | | <ScrollContainer> |
| | | <BasicForm @register="registerForm"> |
| | | |
| | | </BasicForm> |
| | | </ScrollContainer> |
| | | |
| | | </div> |
| | | </TabPane> |
| | | </Tabs> |
| | | <template #footer> |
| | | <Row class="text-center" v-if="activeKey==='1'"> |
| | | <Col span="8"> |
| | | <a-button type="link">编辑</a-button> |
| | | </Col> |
| | | <Col span="8"> |
| | | <a-button type="text" danger>删除</a-button> |
| | | </Col> |
| | | <Col span="8"> |
| | | <a-button type="link" >完成</a-button> |
| | | </Col> |
| | | </Row> |
| | | <Row class="" v-if="activeKey==='2'" justify="end"> |
| | | <Col> |
| | | <a-button type="default">取消</a-button> |
| | | <a-button type="primary">保存</a-button> |
| | | </Col> |
| | | </Row> |
| | | </template> |
| | | </BasicModal> |
| | | </template> |
| | | <script lang="ts" setup> |
| | | import { ref, nextTick } from 'vue'; |
| | | import {BasicModal, useModal, useModalInner} from '@/components/Modal'; |
| | | import { BasicForm, FormSchema, useForm } from '@/components/Form'; |
| | | import {TabPane, Tabs, Row, Col, Divider, Checkbox, Avatar,Empty,Flex,ImagePreviewGroup,Image,Upload} from 'ant-design-vue'; |
| | | import type { UploadProps } from 'ant-design-vue'; |
| | | import { ClockCircleOutlined,HeartOutlined,HeartFilled,EditOutlined,CloseOutlined } from '@ant-design/icons-vue'; |
| | | import ScrollContainer from "@/components/Container/src/ScrollContainer.vue"; |
| | | import { schemas } from './scheduleCommentFormData'; |
| | | |
| | | const activeKey = ref('1'); |
| | | const checked = ref(false); |
| | | |
| | | const props = defineProps({ |
| | | userData: { type: Object }, |
| | | }); |
| | | const modelRef = ref({}); |
| | | const [ |
| | | registerForm, |
| | | // { |
| | | // // setFieldsValue, |
| | | // // setProps |
| | | // }, |
| | | ] = useForm({ |
| | | // labelWidth: 120, |
| | | layout: 'vertical', |
| | | schemas, |
| | | showActionButtonGroup: false, |
| | | actionColOptions: { |
| | | span: 24, |
| | | }, |
| | | }); |
| | | |
| | | const fileList = ref<UploadProps['fileList']>([ |
| | | { |
| | | uid: '-1', |
| | | name: 'xxx.png', |
| | | status: 'done', |
| | | url: 'https://zos.alipayobjects.com/rmsportal/jkjgkEfvpUPVyRjUImniVslZfWPnJuuZ.png', |
| | | thumbUrl: 'https://zos.alipayobjects.com/rmsportal/jkjgkEfvpUPVyRjUImniVslZfWPnJuuZ.png', |
| | | }, |
| | | { |
| | | uid: '-2', |
| | | name: 'yyy.png', |
| | | status: 'done', |
| | | url: 'https://zos.alipayobjects.com/rmsportal/jkjgkEfvpUPVyRjUImniVslZfWPnJuuZ.png', |
| | | thumbUrl: 'https://zos.alipayobjects.com/rmsportal/jkjgkEfvpUPVyRjUImniVslZfWPnJuuZ.png', |
| | | }, |
| | | ]); |
| | | const removeFile = (file) => { |
| | | Logger.log('点击删除',file); |
| | | return false; |
| | | } |
| | | |
| | | const [register,{setModalProps}] = useModalInner((data) => { |
| | | setModalProps({ |
| | | canFullscreen: false, |
| | | showCancelBtn: false, |
| | | showOkBtn: false, |
| | | useWrapper: false, |
| | | wrapperFooterOffset: 0, |
| | | // draggable: false, |
| | | minHeight: 400, |
| | | }); |
| | | data && onDataReceive(data); |
| | | }); |
| | | |
| | | function onTabsChange(key:string) { |
| | | Logger.log('点击切换',key); |
| | | if (key === '1') { |
| | | setModalProps({ |
| | | minHeight: 400, |
| | | }); |
| | | } |
| | | if (key === '2') { |
| | | setModalProps({ |
| | | minHeight: 600, |
| | | }); |
| | | } |
| | | |
| | | } |
| | | |
| | | function onDataReceive(data) { |
| | | console.log('Data Received', data); |
| | | // 方式1; |
| | | // setFieldsValue({ |
| | | // field2: data.data, |
| | | // field1: data.info, |
| | | // }); |
| | | |
| | | // // 方式2 |
| | | modelRef.value = { field2: data.data, field1: data.info }; |
| | | |
| | | // setProps({ |
| | | // model:{ field2: data.data, field1: data.info } |
| | | // }) |
| | | } |
| | | |
| | | function handleVisibleChange(v) { |
| | | v && props.userData && nextTick(() => onDataReceive(props.userData)); |
| | | } |
| | | </script> |
| | | <style lang="less"> |
| | | .schedule-detail-modal { |
| | | .scroll-wrap{ |
| | | height: 240px; |
| | | } |
| | | .ant-modal-body,.ant-modal-header { |
| | | padding: 0; |
| | | margin: 0; |
| | | } |
| | | .ant-modal-footer{ |
| | | margin: 0; |
| | | } |
| | | .ant-modal-header,.ant-modal-footer{ |
| | | border: none; |
| | | } |
| | | .ant-tabs { |
| | | margin: -16px; |
| | | padding: 0 24px; |
| | | } |
| | | .scroll-container{ |
| | | padding-bottom: 0 !important; |
| | | } |
| | | .comment-card{ |
| | | border-bottom: 5px solid #ccc; |
| | | } |
| | | |
| | | .upload-list-inline { |
| | | .ant-upload-list-picture{ |
| | | display:flex; |
| | | .ant-upload-list-item{ |
| | | margin-right: 8px; |
| | | } |
| | | .ant-upload-list-item-container{ |
| | | width: 50%; |
| | | } |
| | | } |
| | | } |
| | | } |
| | | </style> |
| | | |
New file |
| | |
| | | <template> |
| | | <Row class="mb-10px"> |
| | | <Col span="12"> |
| | | <Dropdown :trigger="['click']" arrow @openChange="openChange"> |
| | | <span class="cursor-pointer" @click.prevent> |
| | | {{ dropDownTitle }} |
| | | <BasicArrow :expand="false" down/> |
| | | </span> |
| | | <template #overlay> |
| | | <Menu @click="onMenuItemClick"> |
| | | <MenuItem key="0"> |
| | | <span>未完成</span> |
| | | </MenuItem> |
| | | <MenuItem key="1"> |
| | | <span>已完成</span> |
| | | </MenuItem> |
| | | </Menu> |
| | | </template> |
| | | </Dropdown> |
| | | </Col> |
| | | <Col span="12" :style="'text-align:right'"> |
| | | <Tooltip title="新建日程"> |
| | | <PlusSquareOutlined class="cursor-pointer" style="fontSize:24px;color: #aaa" |
| | | @click="openScheduleModal"/> |
| | | </Tooltip> |
| | | |
| | | </Col> |
| | | </Row> |
| | | <BasicTable |
| | | @register="registerTable" |
| | | @row-click="handleScheduleRowClick" |
| | | > |
| | | <template #bodyCell="{ column, record }"> |
| | | <template v-if="column.key === 'cluesName'"> |
| | | <div> |
| | | <Avatar :size="16" :style="'background-color:'+ record.color"></Avatar> |
| | | <span class="ml-5px"> |
| | | {{ record.cluesName }} |
| | | </span> |
| | | </div> |
| | | </template> |
| | | </template> |
| | | </BasicTable> |
| | | <ScheduleDetailModal @register="registerScheduleModal"></ScheduleDetailModal> |
| | | <div> |
| | | <template v-for="item in projectList" :key="item.title"> |
| | | <Row class="cursor-pointer" :gutter="[22,26]" align="middle"> |
| | | <Col span="12"> |
| | | <Avatar :size="16" :style="'background-color:'+ item.color"></Avatar> |
| | | <span class="ml-5px">{{ item.title }}</span> |
| | | </Col> |
| | | <Col span="12" :style="'text-align:right'"> |
| | | <span>{{ item.content }}</span> |
| | | </Col> |
| | | </Row> |
| | | </template> |
| | | |
| | | </div> |
| | | <!-- <List :class="prefixCls" item-layout="horizontal" :data-source="projectList" :grid="{ column: 1, gutter: 12}" :pagination="pagination" >--> |
| | | <!-- <template #renderItem="{ item }">--> |
| | | <!-- <ListItem>--> |
| | | <!-- --> |
| | | <!-- </ListItem>--> |
| | | |
| | | <!-- </template>--> |
| | | <!--<!– <template v-for="item in projectList" :key="item.title"></template>–>--> |
| | | <!-- </List>--> |
| | | </template> |
| | | <script lang="ts" setup> |
| | | import {List, Avatar, Card, Row, Col, Dropdown, Menu, Tooltip, Tag} from 'ant-design-vue'; |
| | | import {projectList} from './data'; |
| | | import {PlusSquareOutlined} from '@ant-design/icons-vue'; |
| | | import {BasicArrow} from "@/components/Basic"; |
| | | import {ref} from 'vue'; |
| | | import ScheduleDetailModal from './ScheduleDetail.vue'; |
| | | |
| | | const ListItem = List.Item; |
| | | const MenuItem = Menu.Item; |
| | | |
| | | import EventBus from '@/utils/eventBus'; |
| | | import {BasicTable, ColumnChangeParam, TableAction, useTable} from "@/components/Table"; |
| | | import {cluesListApi} from "@/api/clues/table"; |
| | | import {getEditCellColumns, getFormConfig} from "@/views/clues/components/tableData"; |
| | | import {useModal} from "@/components/Modal"; |
| | | |
| | | const [registerScheduleModal, {openModal, setModalProps}] = useModal(); |
| | | const openScheduleModal = () => { |
| | | Logger.log('点击openScheduleModal'); |
| | | EventBus.emit('openScheduleModal', { |
| | | title: '新建任务', |
| | | content: '新建任务内容' |
| | | }); |
| | | }; |
| | | |
| | | const pagination = { |
| | | onChange: (page: number) => { |
| | | console.log(page); |
| | | }, |
| | | pageSize: 3, |
| | | }; |
| | | |
| | | const openChange = (status: boolean) => { |
| | | Logger.log('openChange', status); |
| | | }; |
| | | const dropDownTitle = ref('未完成'); |
| | | const onMenuItemClick = (e: any) => { |
| | | let titles = ['未完成', '已完成']; |
| | | Logger.log('onMenuItemClick', e); |
| | | dropDownTitle.value = titles[e.key]; |
| | | }; |
| | | |
| | | const [ |
| | | registerTable, |
| | | { |
| | | // setLoading, |
| | | // setProps, |
| | | // getColumns, |
| | | // getDataSource, |
| | | // getRawDataSource, |
| | | // reload, |
| | | // getPaginationRef, |
| | | // setPagination, |
| | | // getSelectRows, |
| | | // getSelectRowKeys, |
| | | // setSelectedRowKeys, |
| | | // clearSelectedRowKeys, |
| | | }, |
| | | ] = useTable({ |
| | | canResize: true, |
| | | api: cluesListApi, |
| | | // beforeFetch: (params) => { |
| | | // console.log('beforeFetch', params); |
| | | // params.pageNo = params.page; |
| | | // // return Promise.resolve(params); |
| | | // }, |
| | | showIndexColumn: false, |
| | | columns: [ |
| | | { |
| | | // title: '', |
| | | // defaultHidden: true, |
| | | dataIndex: 'cluesName', |
| | | width: 200 |
| | | }, |
| | | { |
| | | // title: '', |
| | | dataIndex: 'archiveTime', |
| | | width: 200, |
| | | }, |
| | | ], |
| | | // defSort: { |
| | | // pageNo: 1, |
| | | // pageSize: 20, |
| | | // field: 'name', |
| | | // order: 'ascend', |
| | | // }, |
| | | rowKey: 'id', |
| | | // showTableSetting: false, |
| | | // showIndexColumn: false, // 是否显示序号列 |
| | | // useSearchForm: false, // 使用搜索表单 |
| | | // clickToRowSelect: false, |
| | | // formConfig: getFormConfig(), // 搜索表单配置 |
| | | pagination: { |
| | | // pageSize: 20, |
| | | pageSizeOptions: ['10', '20', '50', '100'], |
| | | defaultPageSize: 20, |
| | | // showSizeChanger: true, |
| | | }, |
| | | }); |
| | | |
| | | |
| | | |
| | | function handleScheduleRowClick(e) { |
| | | Logger.log('handleScheduleRowClick', e); |
| | | openModal(true, { |
| | | // record, |
| | | // isUpdate: true, |
| | | }); |
| | | } |
| | | |
| | | const prefixCls = 'account-center-project'; |
| | | </script> |
| | | <style lang="less" > |
| | | |
| | | </style> |
New file |
| | |
| | | export interface ListItem { |
| | | title: string; |
| | | icon: string; |
| | | color?: string; |
| | | } |
| | | |
| | | export interface TabItem { |
| | | key: string; |
| | | name: string; |
| | | component: string; |
| | | } |
| | | |
| | | export const tags: string[] = [ |
| | | '很有想法的', |
| | | '专注设计', |
| | | '川妹子', |
| | | '海纳百川', |
| | | '前端开发', |
| | | 'vue3', |
| | | ]; |
| | | |
| | | export const teams: ListItem[] = [ |
| | | { |
| | | icon: 'ri:alipay-fill', |
| | | title: '科学搬砖组', |
| | | color: '#ff4000', |
| | | }, |
| | | { |
| | | icon: 'emojione-monotone:letter-a', |
| | | title: '中二少年团', |
| | | color: '#7c51b8', |
| | | }, |
| | | { |
| | | icon: 'ri:alipay-fill', |
| | | title: '高逼格设计', |
| | | color: '#00adf7', |
| | | }, |
| | | { |
| | | icon: 'jam:codepen-circle', |
| | | title: '程序员日常', |
| | | color: '#00adf7', |
| | | }, |
| | | { |
| | | icon: 'fa:behance-square', |
| | | title: '科学搬砖组', |
| | | color: '#7c51b8', |
| | | }, |
| | | { |
| | | icon: 'jam:codepen-circle', |
| | | title: '程序员日常', |
| | | color: '#ff4000', |
| | | }, |
| | | ]; |
| | | |
| | | export const details: ListItem[] = [ |
| | | { |
| | | icon: 'ic:outline-contacts', |
| | | title: '交互专家', |
| | | }, |
| | | { |
| | | icon: 'grommet-icons:cluster', |
| | | title: '某某某事业群', |
| | | }, |
| | | { |
| | | icon: 'bx:bx-home-circle', |
| | | title: '福建省厦门市', |
| | | }, |
| | | ]; |
| | | |
| | | export const achieveList: TabItem[] = [ |
| | | { |
| | | key: '1', |
| | | name: '动态', |
| | | component: 'Dynamic', |
| | | }, |
| | | { |
| | | key: '2', |
| | | name: '资料', |
| | | component: 'Detail', |
| | | }, |
| | | { |
| | | key: '3', |
| | | name: '商机', |
| | | component: 'Business', |
| | | }, |
| | | { |
| | | key: '4', |
| | | name: 'Tips', |
| | | component: 'Tips', |
| | | }, |
| | | { |
| | | key: '5', |
| | | name: '文档', |
| | | component: 'Document', |
| | | }, |
| | | ]; |
| | | |
| | | export const actions: any[] = [ |
| | | { icon: 'clarity:star-line', text: '156', color: '#018ffb' }, |
| | | { icon: 'bx:bxs-like', text: '156', color: '#459ae8' }, |
| | | { icon: 'bx:bxs-message-dots', text: '2', color: '#42d27d' }, |
| | | ]; |
| | | |
| | | export const articleList = (() => { |
| | | const result: any[] = []; |
| | | for (let i = 0; i < 4; i++) { |
| | | result.push({ |
| | | title: 'Vben Admin', |
| | | description: ['Vben', '设计语言', 'Typescript'], |
| | | content: '基于Vue Next, TypeScript, Ant Design实现的一套完整的企业级后台管理系统。', |
| | | time: '2020-11-14 11:20', |
| | | }); |
| | | } |
| | | return result; |
| | | })(); |
| | | |
| | | export const applicationList = (() => { |
| | | const result: any[] = []; |
| | | for (let i = 0; i < 8; i++) { |
| | | result.push({ |
| | | title: 'Vben Admin', |
| | | icon: 'emojione-monotone:letter-a', |
| | | color: '#1890ff', |
| | | active: '100', |
| | | new: '1,799', |
| | | download: 'bx:bx-download', |
| | | }); |
| | | } |
| | | return result; |
| | | })(); |
| | | |
| | | export const projectList = (() => { |
| | | const result: any[] = []; |
| | | for (let i = 0; i < 8; i++) { |
| | | result.push({ |
| | | color: '#1890ff', |
| | | title: `测试日程${i + 1}`, |
| | | content: `测试时间 ${i + 1} - ${i + 2}`, |
| | | }); |
| | | } |
| | | return result; |
| | | })(); |
New file |
| | |
| | | <template> |
| | | <div :class="prefixCls"> |
| | | <Row :class="`${prefixCls}-top`"> |
| | | <Col :span="4" :class="`${prefixCls}-col`"> |
| | | <div :class="`${prefixCls}-top__avatar`"> |
| | | <img width="50" :src="avatar" /> |
| | | </div> |
| | | </Col> |
| | | <Col :span="20" :class="`${prefixCls}-col`"> |
| | | <div class="mb-10px"> |
| | | <div class="mb-5px"> |
| | | Vben |
| | | <Icon |
| | | icon="majesticons:open" |
| | | class="mr-15px cursor-pointer" |
| | | @click="" |
| | | :style="{ color: 'hotpink' }" |
| | | :size="16" |
| | | /> |
| | | </div> |
| | | <div>海纳百川,有容乃大</div> |
| | | </div> |
| | | <div class="mb-10px flex"> |
| | | <div> |
| | | <span>跟进人:</span> |
| | | <span>111</span> |
| | | </div> |
| | | <div class="ml-10px flex"> |
| | | <span>客户评分<BasicHelp :text="['评分规则:1,评分=各维度分数(所打分数*该维度权重)的总和;', '2,如只有首次评分,则以首次评分为准;如有两次评分,则取两次评分的平均值。']"/>:</span> |
| | | <span>10</span> |
| | | </div> |
| | | </div> |
| | | <div class=""> |
| | | <template v-for="tag in tags" :key="tag"> |
| | | <Tag class="mb-2"> |
| | | {{ tag }} |
| | | </Tag> |
| | | </template> |
| | | <TagSelector class="pb-10px inline-block mt-10px"></TagSelector> |
| | | </div> |
| | | |
| | | </Col> |
| | | <!-- <Col :span="8" :class="`${prefixCls}-col`">--> |
| | | <!-- <CollapseContainer :class="`${prefixCls}-top__team`" title="团队" :canExpand="false">--> |
| | | <!-- <div v-for="(team, index) in teams" :key="index" :class="`${prefixCls}-top__team-item`">--> |
| | | <!-- <Icon :icon="team.icon" :color="team.color" />--> |
| | | <!-- <span>{{ team.title }}</span>--> |
| | | <!-- </div>--> |
| | | <!-- </CollapseContainer>--> |
| | | <!-- </Col>--> |
| | | </Row> |
| | | <div :class="`${prefixCls}-bottom`"> |
| | | <Tabs> |
| | | <template v-for="item in achieveList" :key="item.key"> |
| | | <TabPane :tab="item.name"> |
| | | |
| | | <ScrollContainer class="scroll-wrap"> |
| | | <component :is="tabs[item.component]" /> |
| | | </ScrollContainer> |
| | | |
| | | </TabPane> |
| | | </template> |
| | | </Tabs> |
| | | </div> |
| | | </div> |
| | | </template> |
| | | |
| | | <script lang="ts" setup> |
| | | import Icon from '@/components/Icon/Icon.vue'; |
| | | import { Col, Row, Tabs, Tag } from 'ant-design-vue'; |
| | | import { computed } from 'vue'; |
| | | import Dynamic from './Dynamic.vue'; |
| | | import Detail from './Detail.vue'; |
| | | import Business from './Business.vue'; |
| | | import Tips from './Tips.vue'; |
| | | import Document from './Document.vue'; |
| | | |
| | | import headerImg from '@/assets/images/header.jpg'; |
| | | import { useUserStore } from '@/store/modules/user'; |
| | | import { achieveList, tags } from './data'; |
| | | import {BasicHelp} from "@/components/Basic"; |
| | | import ScrollContainer from "@/components/Container/src/ScrollContainer.vue"; |
| | | import {TagSelector} from "@/components/TagSelector"; |
| | | |
| | | const userStore = useUserStore(); |
| | | const TabPane = Tabs.TabPane; |
| | | const tabs = { |
| | | Detail, |
| | | Dynamic, |
| | | Business, |
| | | Tips, |
| | | Document, |
| | | }; |
| | | const prefixCls = 'customer-drawer'; |
| | | const avatar = computed(() => userStore.getUserInfo.avatar || headerImg); |
| | | </script> |
| | | <style lang="less" scoped> |
| | | .customer-drawer { |
| | | &-col:not(:last-child) { |
| | | padding: 0 10px; |
| | | |
| | | //&:not(:last-child) { |
| | | // border-right: 1px dashed rgb(206 206 206 / 50%); |
| | | //} |
| | | } |
| | | |
| | | &-top { |
| | | //margin: 16px 16px 12px; |
| | | //padding: 10px; |
| | | border-radius: 3px; |
| | | background-color: @component-background; |
| | | |
| | | &__avatar { |
| | | text-align: center; |
| | | |
| | | img { |
| | | margin: auto; |
| | | border-radius: 50%; |
| | | } |
| | | |
| | | span { |
| | | display: block; |
| | | font-size: 20px; |
| | | font-weight: 500; |
| | | } |
| | | |
| | | div { |
| | | margin-top: 3px; |
| | | font-size: 12px; |
| | | } |
| | | } |
| | | |
| | | &__detail { |
| | | margin-top: 15px; |
| | | padding-left: 20px; |
| | | } |
| | | |
| | | &__team { |
| | | &-item { |
| | | display: inline-block; |
| | | padding: 4px 24px; |
| | | } |
| | | |
| | | span { |
| | | margin-left: 3px; |
| | | } |
| | | } |
| | | } |
| | | |
| | | &-bottom { |
| | | //margin: 0 16px 16px; |
| | | //padding: 10px; |
| | | border-radius: 3px; |
| | | background-color: @component-background; |
| | | } |
| | | .scroll-wrap{ |
| | | height: calc(100vh - 290px); |
| | | } |
| | | } |
| | | </style> |
New file |
| | |
| | | import dayjs from 'dayjs'; |
| | | import type {Dayjs} from 'dayjs'; |
| | | import {treeOptionsListApi} from "@/api/demo/tree"; |
| | | import {ApiSelect, FormSchema} from '@/components/Form'; |
| | | import { SearchOutlined,CloseOutlined,PlusCircleOutlined } from '@ant-design/icons-vue'; |
| | | import {h} from 'vue'; |
| | | import {PlusOutlined, MinusOutlined, UploadOutlined } from '@ant-design/icons-vue'; |
| | | import { |
| | | FormItem, |
| | | FormItemRest, |
| | | Input, |
| | | Select, |
| | | RadioGroup, |
| | | RadioButton, |
| | | Avatar, |
| | | Image, |
| | | message, |
| | | Upload |
| | | } from "ant-design-vue"; |
| | | import {BasicModal,useModal,useModalInner} from '@/components/Modal'; |
| | | import {optionsListApi} from "@/api/demo/select"; |
| | | import {uploadApi} from "@/api/sys/upload"; |
| | | |
| | | const [registerPersonnelModal, { openModal: openPersonnelModal,setModalProps }] = useModal(); |
| | | |
| | | |
| | | |
| | | type RangeValue = [Dayjs, Dayjs]; |
| | | |
| | | |
| | | export const schemas: FormSchema[] = [ |
| | | { |
| | | field: 'remark', |
| | | component: 'InputTextArea', |
| | | componentProps: { |
| | | placeholder: '请输入内容', |
| | | }, |
| | | label: '添加内容', |
| | | colProps: { |
| | | span: 24, |
| | | }, |
| | | }, |
| | | { |
| | | field: 'field30', |
| | | component: 'ApiSelect', |
| | | label: '通知', |
| | | helpMessage: ['评论通知仅影响谁可以收到评论的通知,', '不影响查看权限,所有日程相关人均可以查看评论内容'], |
| | | // required: true, |
| | | componentProps: { |
| | | // more details see /src/components/Form/src/components/ApiSelect.vue |
| | | api: optionsListApi, |
| | | params: { |
| | | id: 1, |
| | | }, |
| | | mode: 'multiple', |
| | | resultField: 'list', |
| | | // use name as label |
| | | labelField: 'name', |
| | | // use id as value |
| | | valueField: 'id', |
| | | // not request untill to select |
| | | immediate: true, |
| | | onChange: (e, v) => { |
| | | console.log('ApiSelect====>:', e, v); |
| | | }, |
| | | // atfer request callback |
| | | onOptionsChange: (options) => { |
| | | // console.log('get options', options.length, options); |
| | | }, |
| | | }, |
| | | colProps: { |
| | | span: 24, |
| | | }, |
| | | // defaultValue: '0', |
| | | }, |
| | | { |
| | | field: 'remark_image', |
| | | component: 'ImageUpload', |
| | | label: '评论图片', |
| | | subLabel: '(单张图片最大3M,最多上传5张图片)', |
| | | // required: true, |
| | | defaultValue: [ |
| | | 'https://zos.alipayobjects.com/rmsportal/jkjgkEfvpUPVyRjUImniVslZfWPnJuuZ.png', |
| | | ], |
| | | componentProps: { |
| | | api: uploadApi, |
| | | accept: ['png', 'jpeg', 'jpg'], |
| | | helpText: '单张图片最大3M,最多上传5张图片', |
| | | maxSize: 3, //单个文件最大体积,单位 M |
| | | maxNumber: 5, |
| | | }, |
| | | // rules: [ |
| | | // { |
| | | // required: true, |
| | | // trigger: 'change', |
| | | // validator(_, value) { |
| | | // if (isArray(value) && value.length > 0) { |
| | | // return Promise.resolve(); |
| | | // } else { |
| | | // return Promise.reject('请选择上传图片'); |
| | | // } |
| | | // }, |
| | | // }, |
| | | // ], |
| | | }, |
| | | // { |
| | | // field: 'remark_file', |
| | | // component: 'Upload', |
| | | // label: '备注附件', |
| | | // colProps: { |
| | | // span: 24, |
| | | // }, |
| | | // rules: [{ message: '请选择上传文件' }], |
| | | // componentProps: { |
| | | // api: uploadApi, |
| | | // }, |
| | | // }, |
| | | { |
| | | field: 'comment_file', |
| | | component: 'Input', |
| | | // componentProps: { |
| | | // style: {lineHeight: '0'}, |
| | | // }, |
| | | // label: 'renderColContent渲染', |
| | | /**!!!renderColContent 没有FormItem 包裹, 若想要 Form 提交需要带上数据须 <FormItem name={}></FormItem> 包裹: 示例如下*/ |
| | | renderColContent({model, field}, {disabled}) { |
| | | return ( |
| | | <FormItem> |
| | | <Upload> |
| | | <a-button type="primary"> |
| | | <UploadOutlined></UploadOutlined> |
| | | 上传附件 |
| | | </a-button> |
| | | </Upload> |
| | | </FormItem> |
| | | ); |
| | | }, |
| | | colProps: { |
| | | span: 24, |
| | | style: { |
| | | lineHeight: '0', |
| | | }, |
| | | }, |
| | | }, |
| | | // { |
| | | // field: 'field33', |
| | | // component: 'ApiTreeSelect', |
| | | // label: '远程下拉树', |
| | | // helpMessage: ['ApiTreeSelect组件', '使用接口提供的数据生成选项'], |
| | | // required: true, |
| | | // componentProps: { |
| | | // api: treeOptionsListApi, |
| | | // treeCheckable: true, |
| | | // resultField: 'list', |
| | | // onChange: (e, v) => { |
| | | // console.log('ApiTreeSelect====>:', e, v); |
| | | // }, |
| | | // }, |
| | | // colProps: { |
| | | // span: 14, |
| | | // }, |
| | | // }, |
| | | ]; |
New file |
| | |
| | | // import {FormSchema} from '@/components/Table'; |
| | | import {treeOptionsListApi} from "@/api/demo/tree"; |
| | | import {areaRecord} from "@/api/demo/cascader"; |
| | | import dayjs from "dayjs"; |
| | | import {optionsListApi} from "@/api/demo/select"; |
| | | import {Input, FormItem, FormItemRest, Select} from "ant-design-vue"; |
| | | import { ApiSelect, FormSchema } from '@/components/Form'; |
| | | |
| | | import companyType from './drawer-form/companyType'; |
| | | import annualPurchaseAmount from './drawer-form/annualPurchaseAmount'; |
| | | import timeZone from './drawer-form/timeZone'; |
| | | import {uploadApi} from "@/api/sys/upload"; |
| | | |
| | | const custom_typeKey2typeValueRules = (model) => { |
| | | return [ |
| | | { |
| | | // required: true, |
| | | // trigger: 'blur', |
| | | validator: async () => { |
| | | Logger.log('custom_typeKey2typeValueRules', model); |
| | | if (!model.telephoneAreaCode) return Promise.reject('请选择电话区号'); |
| | | if (!model.telephoneNumber) return Promise.reject('请输入电话号码'); |
| | | Promise.resolve(); |
| | | }, |
| | | }, |
| | | ]; |
| | | }; |
| | | |
| | | const add = (model) => { |
| | | console.log('add-',model); |
| | | Logger.log('add=', model); |
| | | }; |
| | | |
| | | export const schemas: FormSchema[] = [ |
| | | { |
| | | field: 'contactName', |
| | | component: 'Input', |
| | | label: '联系人名称', |
| | | colProps: { |
| | | span: 24, |
| | | }, |
| | | rules: [{required: true, trigger: 'blur'}], |
| | | }, |
| | | { |
| | | field: 'email', |
| | | component: 'Input', |
| | | label: '邮箱', |
| | | colProps: { |
| | | span: 24, |
| | | }, |
| | | }, |
| | | { |
| | | field: 'socialPlatform', |
| | | fields: ['socialAccount','socialCount'], |
| | | component: 'Input', |
| | | // label: 'renderColContent渲染', |
| | | /**!!!renderColContent 没有FormItem 包裹, 若想要 Form 提交需要带上数据须 <FormItem name={}></FormItem> 包裹: 示例如下*/ |
| | | renderColContent({model, field}, {disabled}) { |
| | | return ( |
| | | <FormItem |
| | | name="social" |
| | | label="社交平台" |
| | | // rules={[{ trigger: 'blur',required: true, }]} |
| | | // rules={custom_typeKey2typeValueRules(model)} |
| | | > |
| | | <Input.Group compact> |
| | | {/*<Select*/} |
| | | {/* allowClear*/} |
| | | {/* disabled={disabled}*/} |
| | | {/* style="width: 120px"*/} |
| | | {/* v-model:value={model[field]}*/} |
| | | {/*>*/} |
| | | {/* <Select.Option value="公司名称">公司名称</Select.Option>*/} |
| | | {/* <Select.Option value="产品名称">产品名称</Select.Option>*/} |
| | | {/*</Select>*/} |
| | | <ApiSelect |
| | | style="width: 120px" |
| | | v-model:api={optionsListApi} |
| | | placeholder="社交平台" |
| | | showSearch |
| | | v-model:value={model['socialPlatform']} |
| | | optionFilterProp="label" |
| | | resultField="list" |
| | | labelField="name" |
| | | valueField="id" |
| | | /> |
| | | <FormItemRest> |
| | | <Input |
| | | style="width: calc(100% - 120px); margin-left: -1px;" |
| | | placeholder="社交账号" |
| | | v-model:value={model['socialAccount']} |
| | | disabled={disabled} |
| | | // rules={[{ type: 'number',trigger: 'blur',required: true, }]} |
| | | // rules={custom_typeKey2typeValueRules(model)} |
| | | /> |
| | | </FormItemRest> |
| | | {/*<div>*/} |
| | | {/* <a-button shape="circle" onClick={add(model)}>+</a-button>*/} |
| | | {/* /!*<a-button shape="circle" v-if={Number(model['socialCount']) > 0}>-</a-button>*!/*/} |
| | | {/* /!*<a-button shape="circle" v-if={Number(model['socialCount']) === 0} onClick={add}>+</a-button>*!/*/} |
| | | {/* /!*<a-button shape="circle" v-if={Number(model['socialCount']) > 0} onClick={() => del(field)}>-</a-button>*!/*/} |
| | | {/*</div>*/} |
| | | </Input.Group> |
| | | |
| | | </FormItem> |
| | | ); |
| | | }, |
| | | colProps: { |
| | | span: 18, |
| | | }, |
| | | dynamicDisabled: ({values}) => { |
| | | return !!values.field_disabled; |
| | | }, |
| | | }, |
| | | { |
| | | field: '0', |
| | | label: ' ', |
| | | component: 'Input', |
| | | render({model, field}, {disabled}) { |
| | | return ( |
| | | <div> |
| | | <a-button shape="circle" onClick={add(model)}>+</a-button> |
| | | {/*<a-button shape="circle" v-if={Number(model['socialCount']) > 0}>-</a-button>*/} |
| | | {/*<a-button shape="circle" v-if={Number(model['socialCount']) === 0} onClick={add}>+</a-button>*/} |
| | | {/*<a-button shape="circle" v-if={Number(model['socialCount']) > 0} onClick={() => del(field)}>-</a-button>*/} |
| | | </div> |
| | | ); |
| | | }, |
| | | colProps: { |
| | | span: 6, |
| | | }, |
| | | }, |
| | | { |
| | | field: 'telephoneAreaCode', |
| | | fields: ['telephoneNumber'], |
| | | component: 'Input', |
| | | // label: 'renderColContent渲染', |
| | | /**!!!renderColContent 没有FormItem 包裹, 若想要 Form 提交需要带上数据须 <FormItem name={}></FormItem> 包裹: 示例如下*/ |
| | | renderColContent({model, field}, {disabled}) { |
| | | return ( |
| | | <FormItem |
| | | name="telephone" |
| | | label="联系电话" |
| | | // rules={[{ trigger: 'blur',required: true, }]} |
| | | // rules={custom_typeKey2typeValueRules(model)} |
| | | > |
| | | <Input.Group compact> |
| | | |
| | | <ApiSelect |
| | | style="width: 120px" |
| | | v-model:api={optionsListApi} |
| | | placeholder="电话区号" |
| | | showSearch |
| | | v-model:value={model['telephoneAreaCode']} |
| | | optionFilterProp="label" |
| | | resultField="list" |
| | | labelField="name" |
| | | valueField="id" |
| | | // rules={[{ trigger: 'blur',required: true, }]} |
| | | /> |
| | | <FormItemRest> |
| | | <Input |
| | | style="width: calc(100% - 120px); margin-left: -1px;" |
| | | placeholder="电话号码" |
| | | v-model:value={model['telephoneNumber']} |
| | | disabled={disabled} |
| | | // rules={[{ trigger: 'blur',required: true, }]} |
| | | // rules={custom_typeKey2typeValueRules(model)} |
| | | /> |
| | | </FormItemRest> |
| | | </Input.Group> |
| | | </FormItem> |
| | | ); |
| | | }, |
| | | colProps: { |
| | | span: 16, |
| | | }, |
| | | dynamicDisabled: ({values}) => { |
| | | return !!values.field_disabled; |
| | | }, |
| | | }, |
| | | // { |
| | | // field: 'typeKey2', |
| | | // fields: ['typeValue2'], |
| | | // component: 'Input', |
| | | // label: '复合', |
| | | // /**!!!renderColContent 没有FormItem 包裹, 若想要 Form 提交需要带上数据须 <FormItem name={}></FormItem> 包裹: 示例如下*/ |
| | | // render({ model, field }, { disabled }) { |
| | | // return ( |
| | | // <Input.Group> |
| | | // <Select |
| | | // disabled={disabled} |
| | | // style="width: 120px" |
| | | // allowClear |
| | | // v-model:value={model[field]} |
| | | // > |
| | | // <Select.Option value="测试类型">测试类型</Select.Option> |
| | | // <Select.Option value="测试名称">测试名称</Select.Option> |
| | | // </Select> |
| | | // <FormItem name="typeValue2" rules={[{ required: true }]}> |
| | | // <FormItemRest> |
| | | // <Input |
| | | // placeholder="请输入" |
| | | // v-model:value={model['typeValue2']} |
| | | // disabled={disabled} |
| | | // /> |
| | | // </FormItemRest> |
| | | // </FormItem> |
| | | // </Input.Group> |
| | | // ); |
| | | // }, |
| | | // colProps: { |
| | | // span: 12, |
| | | // }, |
| | | // dynamicDisabled: ({values}) => { |
| | | // return !!values.field_disabled; |
| | | // }, |
| | | // }, |
| | | { |
| | | field: 'cluesFrom', |
| | | component: 'ApiTreeSelect', |
| | | label: '线索来源', |
| | | componentProps: { |
| | | api: treeOptionsListApi, |
| | | treeCheckable: true, |
| | | treeCheckStrictly: true, // 父子节点是否不再关联 |
| | | resultField: 'list', |
| | | onChange: (e, v) => { |
| | | console.log('ApiTreeSelect====>:', e, v); |
| | | }, |
| | | }, |
| | | colProps: { |
| | | span: 24, |
| | | }, |
| | | }, |
| | | { |
| | | field: 'abbreviation', |
| | | component: 'Input', |
| | | label: '简称', |
| | | colProps: { |
| | | span: 24, |
| | | }, |
| | | }, |
| | | { |
| | | field: 'field8', |
| | | component: 'ApiCascader', |
| | | label: '国家地区', |
| | | colProps: { |
| | | span: 16, |
| | | }, |
| | | componentProps: { |
| | | api: areaRecord, |
| | | apiParamKey: 'parentCode', |
| | | // dataField: 'data', |
| | | labelField: 'name', |
| | | valueField: 'code', |
| | | initFetchParams: { |
| | | parentCode: '', |
| | | }, |
| | | isLeaf: (record) => { |
| | | return !(record.levelType < 3); |
| | | }, |
| | | onChange: (e, ...v) => { |
| | | console.log('ApiCascader====>:', e, v); |
| | | }, |
| | | }, |
| | | }, |
| | | // { |
| | | // field: 'field9', |
| | | // component: 'ApiCascader', |
| | | // label: '联动ApiCascader', |
| | | // required: true, |
| | | // colProps: { |
| | | // span: 8, |
| | | // }, |
| | | // componentProps: { |
| | | // api: areaRecord, |
| | | // apiParamKey: 'parentCode', |
| | | // // dataField: 'data', |
| | | // labelField: 'name', |
| | | // valueField: 'code', |
| | | // initFetchParams: { |
| | | // parentCode: '', |
| | | // }, |
| | | // isLeaf: (record) => { |
| | | // return !(record.levelType < 3); |
| | | // }, |
| | | // onChange: (e, ...v) => { |
| | | // console.log('ApiCascader====>:', e, v); |
| | | // }, |
| | | // }, |
| | | // }, |
| | | { |
| | | field: 'field30', |
| | | component: 'ApiSelect', |
| | | label: '线索标签', |
| | | // required: true, |
| | | componentProps: { |
| | | // more details see /src/components/Form/src/components/ApiSelect.vue |
| | | api: optionsListApi, |
| | | params: { |
| | | id: 1, |
| | | }, |
| | | mode: 'multiple', |
| | | resultField: 'list', |
| | | // use name as label |
| | | labelField: 'name', |
| | | // use id as value |
| | | valueField: 'id', |
| | | // not request untill to select |
| | | immediate: true, |
| | | onChange: (e, v) => { |
| | | console.log('ApiSelect====>:', e, v); |
| | | }, |
| | | // atfer request callback |
| | | onOptionsChange: (options) => { |
| | | // console.log('get options', options.length, options); |
| | | }, |
| | | }, |
| | | colProps: { |
| | | span: 16, |
| | | }, |
| | | // defaultValue: '0', |
| | | }, |
| | | { |
| | | field: 'companyName', |
| | | component: 'Input', |
| | | label: '公司名称', |
| | | colProps: { |
| | | span: 16, |
| | | }, |
| | | }, |
| | | |
| | | { |
| | | field: 'customerCode', |
| | | component: 'Input', |
| | | label: '客户代码(与生产单的客户代码一致)', |
| | | colProps: { |
| | | span: 24, |
| | | }, |
| | | }, |
| | | { |
| | | field: '', |
| | | defaultValue: '', |
| | | component: 'Input', |
| | | // label: 'renderColContent渲染', |
| | | /**!!!renderColContent 没有FormItem 包裹, 若想要 Form 提交需要带上数据须 <FormItem name={}></FormItem> 包裹: 示例如下*/ |
| | | renderColContent({model, field}, {disabled}) { |
| | | return ( |
| | | <div class="font-size-16px mb-10px">其他</div> |
| | | ); |
| | | }, |
| | | colProps: { |
| | | span: 24, |
| | | }, |
| | | }, |
| | | { |
| | | component: 'Select', |
| | | label: '公司类型', |
| | | field: 'companyType', |
| | | colProps: {span: 16}, |
| | | componentProps: { |
| | | options: companyType, |
| | | }, |
| | | // defaultValue: '1' |
| | | }, |
| | | { |
| | | component: 'Select', |
| | | label: '采购意向', |
| | | field: 'purchasingIntention', |
| | | colProps: {span: 16}, |
| | | componentProps: { |
| | | options: [ |
| | | { |
| | | label: '未知', |
| | | value: '1', |
| | | }, |
| | | { |
| | | label: '低', |
| | | value: '2', |
| | | }, |
| | | { |
| | | label: '中', |
| | | value: '3', |
| | | }, |
| | | { |
| | | label: '高', |
| | | value: '4', |
| | | }, |
| | | ], |
| | | }, |
| | | }, |
| | | { |
| | | component: 'Select', |
| | | label: '年采购额', |
| | | field: 'annualPurchaseAmount', |
| | | colProps: {span: 16}, |
| | | componentProps: { |
| | | options: annualPurchaseAmount, |
| | | }, |
| | | }, |
| | | { |
| | | component: 'Select', |
| | | label: '时区', |
| | | field: 'timeZone', |
| | | colProps: {span: 16}, |
| | | componentProps: { |
| | | options: timeZone, |
| | | }, |
| | | }, |
| | | { |
| | | field: 'searchKeywords', |
| | | component: 'Input', |
| | | label: '搜索关键词', |
| | | colProps: { |
| | | span: 16, |
| | | }, |
| | | }, |
| | | { |
| | | field: 'detailedAddress', |
| | | component: 'Input', |
| | | label: '详细地址', |
| | | colProps: { |
| | | span: 24, |
| | | }, |
| | | }, |
| | | { |
| | | field: 'image', |
| | | component: 'ImageUpload', |
| | | label: '上传图片', |
| | | subLabel: '(单张图片最大3M,最多上传5张图片)', |
| | | // required: true, |
| | | defaultValue: [ |
| | | 'https://zos.alipayobjects.com/rmsportal/jkjgkEfvpUPVyRjUImniVslZfWPnJuuZ.png', |
| | | ], |
| | | componentProps: { |
| | | api: uploadApi, |
| | | accept: ['png', 'jpeg', 'jpg'], |
| | | helpText: '单张图片最大3M,最多上传5张图片', |
| | | maxSize: 3, //单个文件最大体积,单位 M |
| | | maxNumber: 5, |
| | | }, |
| | | // rules: [ |
| | | // { |
| | | // required: true, |
| | | // trigger: 'change', |
| | | // validator(_, value) { |
| | | // if (isArray(value) && value.length > 0) { |
| | | // return Promise.resolve(); |
| | | // } else { |
| | | // return Promise.reject('请选择上传图片'); |
| | | // } |
| | | // }, |
| | | // }, |
| | | // ], |
| | | }, |
| | | { |
| | | field: 'cluesNotes', |
| | | component: 'InputTextArea', |
| | | label: '线索备注', |
| | | colProps: { |
| | | span: 24, |
| | | }, |
| | | }, |
| | | { |
| | | component: 'Select', |
| | | label: '规模', |
| | | field: 'numberOfPeople', |
| | | colProps: {span: 16}, |
| | | componentProps: { |
| | | options: [ |
| | | { |
| | | label: '少于59人', |
| | | value: '1', |
| | | }, |
| | | { |
| | | label: '60-149人', |
| | | value: '2', |
| | | }, |
| | | { |
| | | label: '150-499人', |
| | | value: '3', |
| | | }, |
| | | { |
| | | label: '500-999人', |
| | | value: '4', |
| | | }, |
| | | { |
| | | label: '1000-4999人', |
| | | value: '5', |
| | | }, |
| | | { |
| | | label: '5000人以上', |
| | | value: '6', |
| | | }, |
| | | ], |
| | | }, |
| | | }, |
| | | { |
| | | field: 'salesman', |
| | | component: 'Input', |
| | | label: '业务员', |
| | | colProps: { |
| | | span: 16, |
| | | }, |
| | | }, |
| | | { |
| | | component: 'Select', |
| | | label: '访问来源', |
| | | field: 'visitSource', |
| | | colProps: {span: 24}, |
| | | componentProps: { |
| | | options: [ |
| | | { |
| | | label: '广告投放', |
| | | value: '1', |
| | | }, |
| | | { |
| | | label: '自然流量', |
| | | value: '2', |
| | | }, |
| | | { |
| | | label: '社交网站', |
| | | value: '3', |
| | | }, |
| | | { |
| | | label: '直接访问', |
| | | value: '4', |
| | | }, |
| | | { |
| | | label: '邮件', |
| | | value: '5', |
| | | }, |
| | | { |
| | | label: '其他', |
| | | value: '6', |
| | | }, |
| | | ], |
| | | }, |
| | | }, |
| | | { |
| | | field: 'field12', |
| | | component: 'ApiCascader', |
| | | label: '主营产品', |
| | | colProps: { span: 24 }, |
| | | componentProps: { |
| | | api: areaRecord, |
| | | apiParamKey: 'parentCode', |
| | | showCheckedStrategy: 'SHOW_CHILD', |
| | | labelField: 'name', |
| | | valueField: 'code', |
| | | multiple: true, |
| | | initFetchParams: { |
| | | parentCode: '', |
| | | }, |
| | | isLeaf: (record) => { |
| | | return !(record.levelType < 3); |
| | | }, |
| | | onChange: (e, ...v) => { |
| | | Logger.log('ApiCascader====> e:', e); |
| | | Logger.log('ApiCascader====> v:', v); |
| | | }, |
| | | }, |
| | | }, |
| | | { |
| | | field: 'ipAddress', |
| | | component: 'ApiSelect', |
| | | label: '访客IP所在地', |
| | | // required: true, |
| | | componentProps: { |
| | | // more details see /src/components/Form/src/components/ApiSelect.vue |
| | | api: optionsListApi, |
| | | params: { |
| | | id: 1, |
| | | }, |
| | | resultField: 'list', |
| | | // use name as label |
| | | labelField: 'name', |
| | | // use id as value |
| | | valueField: 'id', |
| | | // not request untill to select |
| | | immediate: true, |
| | | onChange: (e, v) => { |
| | | console.log('ApiSelect====>:', e, v); |
| | | }, |
| | | // atfer request callback |
| | | onOptionsChange: (options) => { |
| | | // console.log('get options', options.length, options); |
| | | }, |
| | | }, |
| | | colProps: { |
| | | span: 20, |
| | | }, |
| | | // defaultValue: '0', |
| | | }, |
| | | { |
| | | field: 'field1', |
| | | component: 'RadioButtonGroup', |
| | | componentProps: { |
| | | options: [ |
| | | {label: 'Apple', value: 'Apple'}, |
| | | {label: 'Pear', value: 'Pear'}, |
| | | {label: 'Orange', value: 'Orange', disabled: true}, |
| | | ], |
| | | }, |
| | | |
| | | label: '', |
| | | colProps: { |
| | | span: 24, |
| | | }, |
| | | }, |
| | | { |
| | | field: 'field2', |
| | | component: 'Checkbox', |
| | | // suffix:'全天事件', |
| | | subLabel: '', |
| | | colProps: { |
| | | span: 6, |
| | | }, |
| | | renderComponentContent: '全天事件', |
| | | // componentProps: { |
| | | // options: [ |
| | | // { |
| | | // label: '全天事件', |
| | | // value: '1', |
| | | // } |
| | | // ], |
| | | // }, |
| | | }, |
| | | { |
| | | field: '[startDate, endDate]', |
| | | label: '起止时间', |
| | | component: 'RangePicker', |
| | | componentProps: { |
| | | format: 'YYYY-MM-DD', |
| | | placeholder: ['开始日期', '结束日期'], |
| | | }, |
| | | colProps: {span: 24}, |
| | | }, |
| | | |
| | | { |
| | | field: 'field3', |
| | | component: 'DatePicker', |
| | | label: '直到', |
| | | colProps: { |
| | | span: 10, |
| | | offset: 2, |
| | | }, |
| | | componentProps: { |
| | | style: {width: '100%'}, |
| | | disabledDate: (currentDate) => { |
| | | // Logger.log('currentDate',currentDate) |
| | | // 禁用今天之前的天数 |
| | | return currentDate && currentDate < dayjs().subtract(1, 'day'); |
| | | } |
| | | }, |
| | | required: true, |
| | | ifShow: ({values}) => { |
| | | // Logger.log('vvv',values) |
| | | return ['2', '3', '4'].includes(values.date1); |
| | | }, |
| | | }, |
| | | { |
| | | field: 'remindTime2', |
| | | component: 'DatePicker', |
| | | label: '', |
| | | colProps: { |
| | | span: 6, |
| | | offset: 2, |
| | | }, |
| | | componentProps: { |
| | | // disabledDate:(currentDate)=>{ |
| | | // // Logger.log('currentDate',currentDate) |
| | | // // 禁用今天之前的天数 |
| | | // return currentDate && currentDate < dayjs().subtract(1, 'day'); |
| | | // } |
| | | }, |
| | | dynamicRules: ({values}) => { |
| | | return [ |
| | | { |
| | | // required: true, |
| | | validator: (_, value) => { |
| | | if (values.remindTime === '6') { |
| | | if (!value) { |
| | | return Promise.reject('不能为空'); |
| | | } |
| | | } |
| | | |
| | | return Promise.resolve(); |
| | | }, |
| | | }, |
| | | ]; |
| | | }, |
| | | show: ({values}) => { |
| | | // Logger.log('vvv',values) |
| | | return values.remindTime === '6'; |
| | | }, |
| | | }, |
| | | ]; |
New file |
| | |
| | | import { BasicColumn, FormSchema } from '@/components/Table'; |
| | | import { h } from 'vue'; |
| | | import { Switch } from 'ant-design-vue'; |
| | | import { setRoleStatus } from '@/api/demo/system'; |
| | | import { useMessage } from '@/hooks/web/useMessage'; |
| | | |
| | | type CheckedType = boolean | string | number; |
| | | export const columns: BasicColumn[] = [ |
| | | { |
| | | title: '角色名称', |
| | | dataIndex: 'roleName', |
| | | width: 200, |
| | | }, |
| | | { |
| | | title: '角色值', |
| | | dataIndex: 'roleValue', |
| | | width: 180, |
| | | }, |
| | | { |
| | | title: '排序', |
| | | dataIndex: 'orderNo', |
| | | width: 50, |
| | | }, |
| | | { |
| | | title: '状态', |
| | | dataIndex: 'status', |
| | | width: 120, |
| | | customRender: ({ record }) => { |
| | | if (!Reflect.has(record, 'pendingStatus')) { |
| | | record.pendingStatus = false; |
| | | } |
| | | return h(Switch, { |
| | | checked: record.status === '1', |
| | | checkedChildren: '停用', |
| | | unCheckedChildren: '启用', |
| | | loading: record.pendingStatus, |
| | | onChange(checked: CheckedType) { |
| | | record.pendingStatus = true; |
| | | const newStatus = checked ? '1' : '0'; |
| | | const { createMessage } = useMessage(); |
| | | setRoleStatus(record.id, newStatus) |
| | | .then(() => { |
| | | record.status = newStatus; |
| | | createMessage.success(`已成功修改角色状态`); |
| | | }) |
| | | .catch(() => { |
| | | createMessage.error('修改角色状态失败'); |
| | | }) |
| | | .finally(() => { |
| | | record.pendingStatus = false; |
| | | }); |
| | | }, |
| | | }); |
| | | }, |
| | | }, |
| | | { |
| | | title: '创建时间', |
| | | dataIndex: 'createTime', |
| | | width: 180, |
| | | }, |
| | | { |
| | | title: '备注', |
| | | dataIndex: 'remark', |
| | | }, |
| | | ]; |
| | | |
| | | export const searchFormSchema: FormSchema[] = [ |
| | | { |
| | | field: 'roleNme', |
| | | label: '角色名称', |
| | | component: 'Input', |
| | | colProps: { span: 8 }, |
| | | }, |
| | | { |
| | | field: 'status', |
| | | label: '状态', |
| | | component: 'Select', |
| | | componentProps: { |
| | | options: [ |
| | | { label: '启用', value: '1' }, |
| | | { label: '停用', value: '0' }, |
| | | ], |
| | | }, |
| | | colProps: { span: 8 }, |
| | | }, |
| | | ]; |
| | | |
| | | export const formSchema: FormSchema[] = [ |
| | | { |
| | | field: 'roleName', |
| | | label: '角色名称', |
| | | required: true, |
| | | component: 'Input', |
| | | }, |
| | | { |
| | | field: 'roleValue', |
| | | label: '角色值', |
| | | required: true, |
| | | component: 'Input', |
| | | }, |
| | | { |
| | | field: 'status', |
| | | label: '状态', |
| | | component: 'RadioButtonGroup', |
| | | defaultValue: '0', |
| | | componentProps: { |
| | | options: [ |
| | | { label: '启用', value: '1' }, |
| | | { label: '停用', value: '0' }, |
| | | ], |
| | | }, |
| | | }, |
| | | { |
| | | label: '备注', |
| | | field: 'remark', |
| | | component: 'InputTextArea', |
| | | }, |
| | | { |
| | | label: ' ', |
| | | field: 'menu', |
| | | slot: 'menu', |
| | | }, |
| | | ]; |
New file |
| | |
| | | // import {FormSchema} from '@/components/Table'; |
| | | import {treeOptionsListApi} from "@/api/demo/tree"; |
| | | import {areaRecord} from "@/api/demo/cascader"; |
| | | import dayjs from "dayjs"; |
| | | import {optionsListApi} from "@/api/demo/select"; |
| | | import {Input, FormItem, FormItemRest} from "ant-design-vue"; |
| | | import { ApiSelect, FormSchema } from '@/components/Form'; |
| | | |
| | | import companyType from './drawer-form/companyType'; |
| | | import annualPurchaseAmount from './drawer-form/annualPurchaseAmount'; |
| | | import timeZone from './drawer-form/timeZone'; |
| | | import {uploadApi} from "@/api/sys/upload"; |
| | | |
| | | // const custom_typeKey2typeValueRules = (model) => { |
| | | // return [ |
| | | // { |
| | | // // required: true, |
| | | // // trigger: 'blur', |
| | | // validator: async () => { |
| | | // Logger.log('custom_typeKey2typeValueRules', model); |
| | | // if (!model.typeKey) return Promise.reject('请选择类型'); |
| | | // if (!model.typeValue) return Promise.reject('请输入数据'); |
| | | // Promise.resolve(); |
| | | // }, |
| | | // }, |
| | | // ]; |
| | | // }; |
| | | |
| | | export const schemas: FormSchema[] = [ |
| | | { |
| | | field: 'field0', |
| | | component: 'Input', |
| | | label: '公司网址', |
| | | colProps: { |
| | | span: 24, |
| | | }, |
| | | }, |
| | | { |
| | | field: 'cluesName', |
| | | component: 'Input', |
| | | label: '线索名称', |
| | | colProps: { |
| | | span: 24, |
| | | }, |
| | | rules: [{required: true, trigger: 'blur'}], |
| | | }, |
| | | { |
| | | field: 'cluesFrom', |
| | | component: 'ApiTreeSelect', |
| | | label: '线索来源', |
| | | componentProps: { |
| | | api: treeOptionsListApi, |
| | | treeCheckable: true, |
| | | treeCheckStrictly: true, // 父子节点是否不再关联 |
| | | resultField: 'list', |
| | | onChange: (e, v) => { |
| | | console.log('ApiTreeSelect====>:', e, v); |
| | | }, |
| | | }, |
| | | colProps: { |
| | | span: 24, |
| | | }, |
| | | }, |
| | | { |
| | | field: 'abbreviation', |
| | | component: 'Input', |
| | | label: '简称', |
| | | colProps: { |
| | | span: 24, |
| | | }, |
| | | }, |
| | | { |
| | | field: 'field8', |
| | | component: 'ApiCascader', |
| | | label: '国家地区', |
| | | colProps: { |
| | | span: 16, |
| | | }, |
| | | componentProps: { |
| | | api: areaRecord, |
| | | apiParamKey: 'parentCode', |
| | | // dataField: 'data', |
| | | labelField: 'name', |
| | | valueField: 'code', |
| | | initFetchParams: { |
| | | parentCode: '', |
| | | }, |
| | | isLeaf: (record) => { |
| | | return !(record.levelType < 3); |
| | | }, |
| | | onChange: (e, ...v) => { |
| | | console.log('ApiCascader====>:', e, v); |
| | | }, |
| | | }, |
| | | }, |
| | | // { |
| | | // field: 'field9', |
| | | // component: 'ApiCascader', |
| | | // label: '联动ApiCascader', |
| | | // required: true, |
| | | // colProps: { |
| | | // span: 8, |
| | | // }, |
| | | // componentProps: { |
| | | // api: areaRecord, |
| | | // apiParamKey: 'parentCode', |
| | | // // dataField: 'data', |
| | | // labelField: 'name', |
| | | // valueField: 'code', |
| | | // initFetchParams: { |
| | | // parentCode: '', |
| | | // }, |
| | | // isLeaf: (record) => { |
| | | // return !(record.levelType < 3); |
| | | // }, |
| | | // onChange: (e, ...v) => { |
| | | // console.log('ApiCascader====>:', e, v); |
| | | // }, |
| | | // }, |
| | | // }, |
| | | { |
| | | field: 'field30', |
| | | component: 'ApiSelect', |
| | | label: '线索标签', |
| | | // required: true, |
| | | componentProps: { |
| | | // more details see /src/components/Form/src/components/ApiSelect.vue |
| | | api: optionsListApi, |
| | | params: { |
| | | id: 1, |
| | | }, |
| | | mode: 'multiple', |
| | | resultField: 'list', |
| | | // use name as label |
| | | labelField: 'name', |
| | | // use id as value |
| | | valueField: 'id', |
| | | // not request untill to select |
| | | immediate: true, |
| | | onChange: (e, v) => { |
| | | console.log('ApiSelect====>:', e, v); |
| | | }, |
| | | // atfer request callback |
| | | onOptionsChange: (options) => { |
| | | // console.log('get options', options.length, options); |
| | | }, |
| | | }, |
| | | colProps: { |
| | | span: 16, |
| | | }, |
| | | // defaultValue: '0', |
| | | }, |
| | | { |
| | | field: 'companyName', |
| | | component: 'Input', |
| | | label: '公司名称', |
| | | colProps: { |
| | | span: 16, |
| | | }, |
| | | }, |
| | | { |
| | | field: 'typeKey', |
| | | defaultValue: '公司名称', |
| | | fields: ['typeValue'], |
| | | defaultValueObj: {typeValue: ''}, |
| | | component: 'Input', |
| | | // label: 'renderColContent渲染', |
| | | /**!!!renderColContent 没有FormItem 包裹, 若想要 Form 提交需要带上数据须 <FormItem name={}></FormItem> 包裹: 示例如下*/ |
| | | renderColContent({model, field}, {disabled}) { |
| | | return ( |
| | | <FormItem |
| | | name="typeKey" |
| | | label="座机" |
| | | // rules={[{ trigger: 'blur',required: true, }]} |
| | | // rules={custom_typeKey2typeValueRules(model)} |
| | | > |
| | | <Input.Group compact> |
| | | {/*<Select*/} |
| | | {/* allowClear*/} |
| | | {/* disabled={disabled}*/} |
| | | {/* style="width: 120px"*/} |
| | | {/* v-model:value={model[field]}*/} |
| | | {/*>*/} |
| | | {/* <Select.Option value="公司名称">公司名称</Select.Option>*/} |
| | | {/* <Select.Option value="产品名称">产品名称</Select.Option>*/} |
| | | {/*</Select>*/} |
| | | <ApiSelect |
| | | style="width: 120px" |
| | | v-model:api={optionsListApi} |
| | | showSearch |
| | | v-model:value={model['field']} |
| | | optionFilterProp="label" |
| | | resultField="list" |
| | | labelField="name" |
| | | valueField="id" |
| | | /> |
| | | <FormItemRest> |
| | | <Input |
| | | style="width: calc(100% - 120px); margin-left: -1px;" |
| | | placeholder="电话号码" |
| | | v-model:value={model['typeValue']} |
| | | disabled={disabled} |
| | | // rules={[{ type: 'number',trigger: 'blur',required: true, }]} |
| | | // rules={custom_typeKey2typeValueRules(model)} |
| | | /> |
| | | </FormItemRest> |
| | | </Input.Group> |
| | | </FormItem> |
| | | ); |
| | | }, |
| | | colProps: { |
| | | span: 16, |
| | | }, |
| | | dynamicDisabled: ({values}) => { |
| | | return !!values.field_disabled; |
| | | }, |
| | | }, |
| | | { |
| | | field: 'customerCode', |
| | | component: 'Input', |
| | | label: '客户代码(与生产单的客户代码一致)', |
| | | colProps: { |
| | | span: 24, |
| | | }, |
| | | }, |
| | | { |
| | | field: '', |
| | | defaultValue: '', |
| | | component: 'Input', |
| | | // label: 'renderColContent渲染', |
| | | /**!!!renderColContent 没有FormItem 包裹, 若想要 Form 提交需要带上数据须 <FormItem name={}></FormItem> 包裹: 示例如下*/ |
| | | renderColContent({model, field}, {disabled}) { |
| | | return ( |
| | | <div class="font-size-16px mb-10px">其他</div> |
| | | ); |
| | | }, |
| | | colProps: { |
| | | span: 24, |
| | | }, |
| | | }, |
| | | { |
| | | component: 'Select', |
| | | label: '公司类型', |
| | | field: 'companyType', |
| | | colProps: {span: 16}, |
| | | componentProps: { |
| | | options: companyType, |
| | | }, |
| | | defaultValue: '1' |
| | | }, |
| | | { |
| | | component: 'Select', |
| | | label: '采购意向', |
| | | field: 'purchasingIntention', |
| | | colProps: {span: 16}, |
| | | componentProps: { |
| | | options: [ |
| | | { |
| | | label: '未知', |
| | | value: '1', |
| | | }, |
| | | { |
| | | label: '低', |
| | | value: '2', |
| | | }, |
| | | { |
| | | label: '中', |
| | | value: '3', |
| | | }, |
| | | { |
| | | label: '高', |
| | | value: '4', |
| | | }, |
| | | ], |
| | | }, |
| | | }, |
| | | { |
| | | component: 'Select', |
| | | label: '年采购额', |
| | | field: 'annualPurchaseAmount', |
| | | colProps: {span: 16}, |
| | | componentProps: { |
| | | options: annualPurchaseAmount, |
| | | }, |
| | | }, |
| | | { |
| | | component: 'Select', |
| | | label: '时区', |
| | | field: 'timeZone', |
| | | colProps: {span: 16}, |
| | | componentProps: { |
| | | options: timeZone, |
| | | }, |
| | | }, |
| | | { |
| | | field: 'searchKeywords', |
| | | component: 'Input', |
| | | label: '搜索关键词', |
| | | colProps: { |
| | | span: 16, |
| | | }, |
| | | }, |
| | | { |
| | | field: 'detailedAddress', |
| | | component: 'Input', |
| | | label: '详细地址', |
| | | colProps: { |
| | | span: 24, |
| | | }, |
| | | }, |
| | | { |
| | | field: 'image', |
| | | component: 'ImageUpload', |
| | | label: '上传图片', |
| | | subLabel: '(单张图片最大3M,最多上传5张图片)', |
| | | // required: true, |
| | | defaultValue: [ |
| | | 'https://zos.alipayobjects.com/rmsportal/jkjgkEfvpUPVyRjUImniVslZfWPnJuuZ.png', |
| | | ], |
| | | componentProps: { |
| | | api: uploadApi, |
| | | accept: ['png', 'jpeg', 'jpg'], |
| | | helpText: '单张图片最大3M,最多上传5张图片', |
| | | maxSize: 3, //单个文件最大体积,单位 M |
| | | maxNumber: 5, |
| | | }, |
| | | // rules: [ |
| | | // { |
| | | // required: true, |
| | | // trigger: 'change', |
| | | // validator(_, value) { |
| | | // if (isArray(value) && value.length > 0) { |
| | | // return Promise.resolve(); |
| | | // } else { |
| | | // return Promise.reject('请选择上传图片'); |
| | | // } |
| | | // }, |
| | | // }, |
| | | // ], |
| | | }, |
| | | { |
| | | field: 'cluesNotes', |
| | | component: 'InputTextArea', |
| | | label: '线索备注', |
| | | colProps: { |
| | | span: 24, |
| | | }, |
| | | }, |
| | | { |
| | | component: 'Select', |
| | | label: '规模', |
| | | field: 'numberOfPeople', |
| | | colProps: {span: 16}, |
| | | componentProps: { |
| | | options: [ |
| | | { |
| | | label: '少于59人', |
| | | value: '1', |
| | | }, |
| | | { |
| | | label: '60-149人', |
| | | value: '2', |
| | | }, |
| | | { |
| | | label: '150-499人', |
| | | value: '3', |
| | | }, |
| | | { |
| | | label: '500-999人', |
| | | value: '4', |
| | | }, |
| | | { |
| | | label: '1000-4999人', |
| | | value: '5', |
| | | }, |
| | | { |
| | | label: '5000人以上', |
| | | value: '6', |
| | | }, |
| | | ], |
| | | }, |
| | | }, |
| | | { |
| | | field: 'salesman', |
| | | component: 'Input', |
| | | label: '业务员', |
| | | colProps: { |
| | | span: 16, |
| | | }, |
| | | }, |
| | | { |
| | | component: 'Select', |
| | | label: '访问来源', |
| | | field: 'visitSource', |
| | | colProps: {span: 24}, |
| | | componentProps: { |
| | | options: [ |
| | | { |
| | | label: '广告投放', |
| | | value: '1', |
| | | }, |
| | | { |
| | | label: '自然流量', |
| | | value: '2', |
| | | }, |
| | | { |
| | | label: '社交网站', |
| | | value: '3', |
| | | }, |
| | | { |
| | | label: '直接访问', |
| | | value: '4', |
| | | }, |
| | | { |
| | | label: '邮件', |
| | | value: '5', |
| | | }, |
| | | { |
| | | label: '其他', |
| | | value: '6', |
| | | }, |
| | | ], |
| | | }, |
| | | }, |
| | | { |
| | | field: 'field12', |
| | | component: 'ApiCascader', |
| | | label: '主营产品', |
| | | colProps: { span: 24 }, |
| | | componentProps: { |
| | | api: areaRecord, |
| | | apiParamKey: 'parentCode', |
| | | showCheckedStrategy: 'SHOW_CHILD', |
| | | labelField: 'name', |
| | | valueField: 'code', |
| | | multiple: true, |
| | | initFetchParams: { |
| | | parentCode: '', |
| | | }, |
| | | isLeaf: (record) => { |
| | | return !(record.levelType < 3); |
| | | }, |
| | | onChange: (e, ...v) => { |
| | | Logger.log('ApiCascader====> e:', e); |
| | | Logger.log('ApiCascader====> v:', v); |
| | | }, |
| | | }, |
| | | }, |
| | | { |
| | | field: 'ipAddress', |
| | | component: 'ApiSelect', |
| | | label: '访客IP所在地', |
| | | // required: true, |
| | | componentProps: { |
| | | // more details see /src/components/Form/src/components/ApiSelect.vue |
| | | api: optionsListApi, |
| | | params: { |
| | | id: 1, |
| | | }, |
| | | resultField: 'list', |
| | | // use name as label |
| | | labelField: 'name', |
| | | // use id as value |
| | | valueField: 'id', |
| | | // not request untill to select |
| | | immediate: true, |
| | | onChange: (e, v) => { |
| | | console.log('ApiSelect====>:', e, v); |
| | | }, |
| | | // atfer request callback |
| | | onOptionsChange: (options) => { |
| | | // console.log('get options', options.length, options); |
| | | }, |
| | | }, |
| | | colProps: { |
| | | span: 20, |
| | | }, |
| | | // defaultValue: '0', |
| | | }, |
| | | { |
| | | field: 'field1', |
| | | component: 'RadioButtonGroup', |
| | | componentProps: { |
| | | options: [ |
| | | {label: 'Apple', value: 'Apple'}, |
| | | {label: 'Pear', value: 'Pear'}, |
| | | {label: 'Orange', value: 'Orange', disabled: true}, |
| | | ], |
| | | }, |
| | | |
| | | label: '', |
| | | colProps: { |
| | | span: 24, |
| | | }, |
| | | }, |
| | | { |
| | | field: 'field2', |
| | | component: 'Checkbox', |
| | | // suffix:'全天事件', |
| | | subLabel: '', |
| | | colProps: { |
| | | span: 6, |
| | | }, |
| | | renderComponentContent: '全天事件', |
| | | // componentProps: { |
| | | // options: [ |
| | | // { |
| | | // label: '全天事件', |
| | | // value: '1', |
| | | // } |
| | | // ], |
| | | // }, |
| | | }, |
| | | { |
| | | field: '[startDate, endDate]', |
| | | label: '起止时间', |
| | | component: 'RangePicker', |
| | | componentProps: { |
| | | format: 'YYYY-MM-DD', |
| | | placeholder: ['开始日期', '结束日期'], |
| | | }, |
| | | colProps: {span: 24}, |
| | | }, |
| | | |
| | | { |
| | | field: 'field3', |
| | | component: 'DatePicker', |
| | | label: '直到', |
| | | colProps: { |
| | | span: 10, |
| | | offset: 2, |
| | | }, |
| | | componentProps: { |
| | | style: {width: '100%'}, |
| | | disabledDate: (currentDate) => { |
| | | // Logger.log('currentDate',currentDate) |
| | | // 禁用今天之前的天数 |
| | | return currentDate && currentDate < dayjs().subtract(1, 'day'); |
| | | } |
| | | }, |
| | | required: true, |
| | | ifShow: ({values}) => { |
| | | // Logger.log('vvv',values) |
| | | return ['2', '3', '4'].includes(values.date1); |
| | | }, |
| | | }, |
| | | { |
| | | field: 'remindTime2', |
| | | component: 'DatePicker', |
| | | label: '', |
| | | colProps: { |
| | | span: 6, |
| | | offset: 2, |
| | | }, |
| | | componentProps: { |
| | | // disabledDate:(currentDate)=>{ |
| | | // // Logger.log('currentDate',currentDate) |
| | | // // 禁用今天之前的天数 |
| | | // return currentDate && currentDate < dayjs().subtract(1, 'day'); |
| | | // } |
| | | }, |
| | | dynamicRules: ({values}) => { |
| | | return [ |
| | | { |
| | | // required: true, |
| | | validator: (_, value) => { |
| | | if (values.remindTime === '6') { |
| | | if (!value) { |
| | | return Promise.reject('不能为空'); |
| | | } |
| | | } |
| | | |
| | | return Promise.resolve(); |
| | | }, |
| | | }, |
| | | ]; |
| | | }, |
| | | show: ({values}) => { |
| | | // Logger.log('vvv',values) |
| | | return values.remindTime === '6'; |
| | | }, |
| | | }, |
| | | ]; |
New file |
| | |
| | | <template> |
| | | <BasicModal |
| | | v-bind="$attrs" |
| | | @register="register" |
| | | title="重新分配" |
| | | @visible-change="handleVisibleChange" |
| | | @ok="handleSubmit" |
| | | > |
| | | <div class="mb-10px"> |
| | | 将线索【{{cluesName}}】 |
| | | </div> |
| | | <div :class="'pt-3px pr-3px '+ prefixCls"> |
| | | <BasicForm @register="registerForm"></BasicForm> |
| | | </div> |
| | | |
| | | </BasicModal> |
| | | </template> |
| | | <script lang="ts" setup> |
| | | import {ref, nextTick, h, unref} from 'vue'; |
| | | import {BasicModal, useModalInner} from '@/components/Modal'; |
| | | import {BasicForm, useForm} from '@/components/Form'; |
| | | |
| | | import {PlusOutlined, MinusOutlined,PaperClipOutlined} from '@ant-design/icons-vue'; |
| | | import {TreeSelect, Upload} from "ant-design-vue"; |
| | | import {optionsListApi} from "@/api/demo/select"; |
| | | const prefixCls = 'new-follow-up'; |
| | | const props = defineProps({ |
| | | userData: {type: Object}, |
| | | }); |
| | | const modelRef = ref({}); |
| | | const [registerForm,{validate:validate}] = useForm({ |
| | | schemas:[{ |
| | | field: 'cluesStatus', |
| | | component: 'ApiSelect', |
| | | label: '重新分配给', |
| | | colProps: { |
| | | span: 24, |
| | | }, |
| | | required: true, |
| | | componentProps: { |
| | | api: optionsListApi, |
| | | params: { |
| | | id: 1, |
| | | }, |
| | | resultField: 'list', |
| | | // use name as label |
| | | labelField: 'name', |
| | | // use id as value |
| | | valueField: 'id', |
| | | // not request untill to select |
| | | immediate: true, |
| | | onChange: (e, v) => { |
| | | console.log('ApiSelect====>:', e, v); |
| | | }, |
| | | // atfer request callback |
| | | onOptionsChange: (options) => { |
| | | console.log('get options', options.length, options); |
| | | }, |
| | | }, |
| | | defaultValue: '1', |
| | | },], |
| | | showActionButtonGroup: false, |
| | | layout: 'vertical', |
| | | }); |
| | | |
| | | const [register,{ setModalProps, closeModal }] = useModalInner((data) => { |
| | | Logger.log('useModalInner data...', data); |
| | | data && onDataReceive(data); |
| | | setModalProps({ |
| | | // width: 800, |
| | | minHeight: 100, |
| | | canFullscreen: false, |
| | | destroyOnClose: true, |
| | | }); |
| | | }); |
| | | |
| | | |
| | | let cluesName = ref('测试1'); |
| | | function onDataReceive(data) { |
| | | console.log('Data Received', data); |
| | | cluesName.value = data.data.cluesName; |
| | | // 方式1; |
| | | // setFieldsValue({ |
| | | // field2: data.data, |
| | | // field1: data.info, |
| | | // }); |
| | | |
| | | // // 方式2 |
| | | modelRef.value = {field2: data.data, field1: data.info}; |
| | | |
| | | // setProps({ |
| | | // model:{ field2: data.data, field1: data.info } |
| | | // }) |
| | | } |
| | | |
| | | function handleVisibleChange(v) { |
| | | v && props.userData && nextTick(() => onDataReceive(props.userData)); |
| | | } |
| | | |
| | | // let currentFollowUpType = ref('1'); |
| | | // function handleFollowUpTypeChange(value: any) { |
| | | // Logger.log('handleFollowUpTypeChange...', value); |
| | | // } |
| | | |
| | | function removeFile(file: any) { |
| | | Logger.log('remove file...', file); |
| | | } |
| | | |
| | | async function handleSubmit() { |
| | | try { |
| | | const values = await validate(); |
| | | Logger.log('submit values', values); |
| | | setModalProps({ confirmLoading: true }); |
| | | // TODO custom api |
| | | // console.log(values); |
| | | closeModal(); |
| | | } finally { |
| | | setModalProps({ confirmLoading: false }); |
| | | } |
| | | } |
| | | </script> |
| | | |
| | | <style lang="less"> |
| | | |
| | | |
| | | </style> |
| | |
| | | import { optionsListApi } from '@/api/demo/select'; |
| | | import { FormProps, FormSchema, BasicColumn } from '@/components/Table'; |
| | | import { VxeFormItemProps, VxeGridPropTypes } from '@/components/VxeTable'; |
| | | import { ref } from 'vue'; |
| | | import {Input} from 'ant-design-vue'; |
| | | |
| | | import { FormProps, BasicColumn } from '@/components/Table'; |
| | | import {treeOptionsListApi} from "@/api/demo/tree"; |
| | | |
| | | export function getEditCellColumns(): BasicColumn[] { |
| | | return [ |
| | | { |
| | | title: '公司名称', |
| | | dataIndex: 'name', |
| | | edit: true, |
| | | title: '线索名称', |
| | | // defaultHidden: true, |
| | | dataIndex: 'cluesName', |
| | | sorter: true, |
| | | editComponentProps: { |
| | | prefix: '$', |
| | | }, |
| | | width: 200, |
| | | // filters:{ |
| | | // text: '公司名称', |
| | | // value: 'name', |
| | | // } |
| | | // filterSearch: true, |
| | | width: 200 |
| | | }, |
| | | { |
| | | title: '客户标签', |
| | | dataIndex: 'tags', |
| | | edit: true, |
| | | // editComponent: 'ApiSelect', |
| | | // editComponentProps: { |
| | | // api: optionsListApi, |
| | | // resultField: 'list', |
| | | // labelField: 'name', |
| | | // valueField: 'id', |
| | | // }, |
| | | width: 200, |
| | | // editRender: ({ text }) => { |
| | | // return h(Tag, { percent: Number(text) }); |
| | | // }, |
| | | }, |
| | | { |
| | | title: '主要联系人', |
| | | dataIndex: 'name1', |
| | | edit: true, |
| | | // 默认必填校验 |
| | | editRule: true, |
| | | title: '存档时间', |
| | | dataIndex: 'archiveTime', |
| | | sorter: true, |
| | | width: 200, |
| | | }, |
| | | { |
| | | title: '最近动态', |
| | | dataIndex: 'name2', |
| | | title: '状态id', |
| | | dataIndex: 'statusId', |
| | | width: 200, |
| | | }, |
| | | { |
| | | title: '状态内容', |
| | | dataIndex: 'status', |
| | | width: 200, |
| | | }, |
| | | { |
| | | title: '跟进时间', |
| | | dataIndex: 'followUpTime', |
| | | width: 200, |
| | | }, |
| | | { |
| | | title: '无效类型', |
| | | dataIndex: 'failType', |
| | | width: 200, |
| | | }, |
| | | { |
| | | title: '无效状态', |
| | | dataIndex: 'failStatus', |
| | | width: 200, |
| | | }, |
| | | { |
| | | title: '无效状态内容', |
| | | dataIndex: 'failStatusName', |
| | | width: 200, |
| | | }, |
| | | { |
| | | title: '无效原因', |
| | | dataIndex: 'failReason', |
| | | width: 200, |
| | | }, |
| | | { |
| | | title: '进入私海时间', |
| | | dataIndex: 'privateTime', |
| | | width: 200, |
| | | }, |
| | | { |
| | | title: '进入公海时间', |
| | | dataIndex: 'publicTime', |
| | | width: 200, |
| | | }, |
| | | { |
| | | title: '是否为公海线索', |
| | | dataIndex: 'isPublic', |
| | | width: 200, |
| | | }, |
| | | { |
| | | title: '评分', |
| | | dataIndex: 'star', |
| | | width: 200, |
| | | }, |
| | | { |
| | | title: '下次跟进时间', |
| | | dataIndex: 'nextFollowUpTime', |
| | | width: 200, |
| | | }, |
| | | { |
| | | title: '是否有重复内容', |
| | | dataIndex: 'duplicateFlag', |
| | | width: 200, |
| | | }, |
| | | { |
| | | title: '标签', |
| | | dataIndex: 'tagList', |
| | | width: 200, |
| | | }, |
| | | { |
| | | title: '公司网址', |
| | | dataIndex: 'homepage', |
| | | width: 200, |
| | | }, |
| | | { |
| | | title: '线索来源', |
| | | dataIndex: 'originList', |
| | | width: 200, |
| | | }, |
| | | { |
| | | title: '简称', |
| | | dataIndex: 'shortName', |
| | | width: 200, |
| | | }, |
| | | { |
| | | title: '国家', |
| | | dataIndex: 'country', |
| | | width: 200, |
| | | }, |
| | | { |
| | | title: '省份', |
| | | dataIndex: 'province', |
| | | width: 200, |
| | | }, |
| | | { |
| | | title: '地区', |
| | | dataIndex: 'city', |
| | | width: 200, |
| | | }, |
| | | { |
| | | title: '公司名称', |
| | | dataIndex: 'corporate', |
| | | width: 200, |
| | | }, |
| | | { |
| | | title: '公司类型', |
| | | dataIndex: 'bizType', |
| | | width: 200, |
| | | }, |
| | | { |
| | | title: '地区号', |
| | | dataIndex: 'telAreaCode', |
| | | width: 200, |
| | | }, |
| | | { |
| | | title: '座机', |
| | | dataIndex: 'tel', |
| | | width: 200, |
| | | }, |
| | | { |
| | | title: '采购意向', |
| | | dataIndex: 'intentionLevel', |
| | | width: 200, |
| | | }, |
| | | { |
| | | title: '年采购额', |
| | | dataIndex: 'annualProcurement', |
| | | width: 200, |
| | | }, |
| | | { |
| | | title: '时区', |
| | | dataIndex: 'timezone', |
| | | width: 200, |
| | | }, |
| | | { |
| | | title: '详细地址', |
| | | dataIndex: 'address', |
| | | width: 200, |
| | | }, |
| | | { |
| | | title: '搜索关键字', |
| | | dataIndex: 'adKeyword', |
| | | width: 200, |
| | | }, |
| | | { |
| | | title: '图片', |
| | | dataIndex: 'imageList', |
| | | width: 200, |
| | | }, |
| | | { |
| | | title: '线索备注', |
| | | dataIndex: 'hdmeno', |
| | | width: 200, |
| | | }, |
| | | { |
| | | title: '规模', |
| | | dataIndex: 'scaleId', |
| | | width: 200, |
| | | }, |
| | | { |
| | | title: '业务员', |
| | | dataIndex: 'seller', |
| | | width: 200, |
| | | }, |
| | | { |
| | | title: '访问来源', |
| | | dataIndex: 'inquiryOrigin', |
| | | width: 200, |
| | | }, |
| | | { |
| | | title: '主营产品', |
| | | dataIndex: 'categoryIds', |
| | | width: 200, |
| | | }, |
| | | { |
| | | title: '访问IP所在地', |
| | | dataIndex: 'inquiryCountry', |
| | | width: 200, |
| | | }, |
| | | { |
| | | title: '是否已关注', |
| | | dataIndex: 'pinFlag', |
| | | width: 200, |
| | | }, |
| | | |
| | | { |
| | | title: '最近联系人', |
| | | dataIndex: 'id', |
| | |
| | | |
| | | |
| | | |
| | | export function getBasicColumns(): BasicColumn[] { |
| | | return [ |
| | | { |
| | | title: 'ID', |
| | | dataIndex: 'id', |
| | | fixed: 'left', |
| | | width: 200, |
| | | }, |
| | | { |
| | | title: '姓名', |
| | | dataIndex: 'name', |
| | | width: 150, |
| | | filters: [ |
| | | { text: 'Male', value: 'male' }, |
| | | { text: 'Female', value: 'female' }, |
| | | ], |
| | | }, |
| | | { |
| | | title: '地址', |
| | | dataIndex: 'address', |
| | | }, |
| | | { |
| | | title: '编号', |
| | | dataIndex: 'no', |
| | | width: 150, |
| | | sorter: true, |
| | | defaultHidden: true, |
| | | }, |
| | | { |
| | | title: '开始时间', |
| | | width: 150, |
| | | sorter: true, |
| | | dataIndex: 'beginTime', |
| | | }, |
| | | { |
| | | title: '结束时间', |
| | | width: 150, |
| | | sorter: true, |
| | | dataIndex: 'endTime', |
| | | }, |
| | | ]; |
| | | } |
| | | |
| | | export function getBasicShortColumns(): BasicColumn[] { |
| | | return [ |
| | | { |
| | | title: 'ID', |
| | | width: 150, |
| | | dataIndex: 'id', |
| | | sorter: true, |
| | | sortOrder: 'ascend', |
| | | }, |
| | | { |
| | | title: '姓名', |
| | | dataIndex: 'name', |
| | | width: 120, |
| | | }, |
| | | { |
| | | title: '地址', |
| | | dataIndex: 'address', |
| | | }, |
| | | { |
| | | title: '编号', |
| | | dataIndex: 'no', |
| | | width: 80, |
| | | }, |
| | | ]; |
| | | } |
| | | |
| | | export function getMultipleHeaderColumns(): BasicColumn[] { |
| | | const testRef = ref('姓名:'); |
| | | return [ |
| | | { |
| | | title: 'ID', |
| | | dataIndex: 'id', |
| | | width: 200, |
| | | }, |
| | | { |
| | | title: '姓名', |
| | | customHeaderRender() { |
| | | return ( |
| | | <Input placeholder="输入值 更新 自定义title" size="small" v-model:value={testRef.value} /> |
| | | ); |
| | | }, |
| | | dataIndex: 'name', |
| | | width: 120, |
| | | }, |
| | | { |
| | | title: '地址', |
| | | dataIndex: 'address', |
| | | sorter: true, |
| | | children: [ |
| | | { |
| | | title: '编号', |
| | | customHeaderRender(column) { |
| | | // 【自定义渲染的】 |
| | | return ( |
| | | <div> |
| | | _ <span style="background: #f00; color: #fff;">{testRef.value}</span> _ |
| | | {column.customTitle} |
| | | </div> |
| | | ); |
| | | }, |
| | | dataIndex: 'no', |
| | | width: 120, |
| | | filters: [ |
| | | { text: 'Male', value: 'male', children: [] }, |
| | | { text: 'Female', value: 'female', children: [] }, |
| | | ], |
| | | }, |
| | | |
| | | { |
| | | title: '开始时间', |
| | | dataIndex: 'beginTime', |
| | | width: 120, |
| | | }, |
| | | { |
| | | title: '结束时间', |
| | | dataIndex: 'endTime', |
| | | width: 120, |
| | | }, |
| | | ], |
| | | }, |
| | | ]; |
| | | } |
| | | |
| | | export function getCustomHeaderColumns(): BasicColumn[] { |
| | | return [ |
| | | { |
| | | title: 'ID', |
| | | dataIndex: 'id', |
| | | helpMessage: 'headerHelpMessage方式1', |
| | | width: 200, |
| | | }, |
| | | { |
| | | // title: '姓名', |
| | | dataIndex: 'name', |
| | | width: 120, |
| | | }, |
| | | { |
| | | // title: '地址', |
| | | dataIndex: 'address', |
| | | width: 120, |
| | | sorter: true, |
| | | }, |
| | | |
| | | { |
| | | title: '编号', |
| | | dataIndex: 'no', |
| | | width: 120, |
| | | filters: [ |
| | | { text: 'Male', value: 'male', children: [] }, |
| | | { text: 'Female', value: 'female', children: [] }, |
| | | ], |
| | | }, |
| | | { |
| | | title: '开始时间', |
| | | dataIndex: 'beginTime', |
| | | width: 120, |
| | | }, |
| | | { |
| | | title: '结束时间', |
| | | dataIndex: 'endTime', |
| | | width: 120, |
| | | }, |
| | | ]; |
| | | } |
| | | |
| | | const cellContent = (_, index) => ({ |
| | | colSpan: index === 9 ? 0 : 1, |
| | | }); |
| | | |
| | | export function getMergeHeaderColumns(): BasicColumn[] { |
| | | return [ |
| | | { |
| | | title: 'ID', |
| | | dataIndex: 'id', |
| | | width: 300, |
| | | customCell: (_, index) => ({ |
| | | colSpan: index === 9 ? 6 : 1, |
| | | }), |
| | | }, |
| | | { |
| | | title: '姓名', |
| | | dataIndex: 'name', |
| | | width: 300, |
| | | customCell: cellContent, |
| | | }, |
| | | { |
| | | title: '地址', |
| | | dataIndex: 'address', |
| | | colSpan: 2, |
| | | width: 120, |
| | | sorter: true, |
| | | customCell: (_, index) => ({ |
| | | rowSpan: index === 2 ? 2 : 1, |
| | | colSpan: index === 3 || index === 9 ? 0 : 1, |
| | | }), |
| | | }, |
| | | { |
| | | title: '编号', |
| | | dataIndex: 'no', |
| | | colSpan: 0, |
| | | filters: [ |
| | | { text: 'Male', value: 'male', children: [] }, |
| | | { text: 'Female', value: 'female', children: [] }, |
| | | ], |
| | | customCell: cellContent, |
| | | }, |
| | | { |
| | | title: '开始时间', |
| | | dataIndex: 'beginTime', |
| | | width: 200, |
| | | customCell: cellContent, |
| | | }, |
| | | { |
| | | title: '结束时间', |
| | | dataIndex: 'endTime', |
| | | width: 200, |
| | | customCell: cellContent, |
| | | }, |
| | | ]; |
| | | } |
| | | export const getAdvanceSchema = (itemNumber = 6): FormSchema[] => { |
| | | const arr: FormSchema[] = []; |
| | | for (let index = 0; index < itemNumber; index++) { |
| | | arr.push({ |
| | | field: `field${index}`, |
| | | label: `字段${index}`, |
| | | component: 'Input', |
| | | colProps: { |
| | | xl: 12, |
| | | xxl: 8, |
| | | }, |
| | | }); |
| | | } |
| | | return arr; |
| | | }; |
| | | export function getFormConfig(): Partial<FormProps> { |
| | | return { |
| | | labelWidth: 100, |
| | | layout: 'horizontal', |
| | | rowProps: { |
| | | justify: 'end', |
| | | }, |
| | | showResetButton: false, |
| | | showSubmitButton: false, |
| | | schemas: [ |
| | | ...getAdvanceSchema(5), |
| | | { |
| | | field: `field11`, |
| | | label: ``, |
| | | slot: 'custom', |
| | | label: `搜索`, |
| | | component: 'Input', |
| | | colProps: { |
| | | xl: 12, |
| | | xxl: 8, |
| | |
| | | ], |
| | | }; |
| | | } |
| | | export function getBasicData() { |
| | | return (() => { |
| | | const arr: any = []; |
| | | for (let index = 0; index < 40; index++) { |
| | | arr.push({ |
| | | id: `${index}`, |
| | | name: 'John Brown', |
| | | age: `1${index}`, |
| | | no: `${index + 10}`, |
| | | address: 'New York No. 1 Lake ParkNew York No. 1 Lake Park', |
| | | beginTime: new Date().toLocaleString(), |
| | | endTime: new Date().toLocaleString(), |
| | | }); |
| | | } |
| | | return arr; |
| | | })(); |
| | | } |
| | | |
| | | export function getTreeTableData() { |
| | | return (() => { |
| | | const arr: any = []; |
| | | for (let index = 0; index < 40; index++) { |
| | | arr.push({ |
| | | id: `${index}`, |
| | | name: 'John Brown', |
| | | age: `1${index}`, |
| | | no: `${index + 10}`, |
| | | address: 'New York No. 1 Lake ParkNew York No. 1 Lake Park', |
| | | beginTime: new Date().toLocaleString(), |
| | | endTime: new Date().toLocaleString(), |
| | | children: [ |
| | | { |
| | | id: `l2-${index}-1`, |
| | | name: 'John Brown', |
| | | age: `1`, |
| | | no: `${index + 10}`, |
| | | address: 'New York No. 1 Lake ParkNew York No. 1 Lake Park', |
| | | beginTime: new Date().toLocaleString(), |
| | | endTime: new Date().toLocaleString(), |
| | | children: [ |
| | | { |
| | | id: `l3-${index}-1-1`, |
| | | name: 'John Brown', |
| | | age: `11`, |
| | | no: `11`, |
| | | address: 'New York No. 1 Lake ParkNew York No. 1 Lake Park', |
| | | beginTime: new Date().toLocaleString(), |
| | | endTime: new Date().toLocaleString(), |
| | | }, |
| | | { |
| | | id: `l3-${index}-1-2`, |
| | | name: 'John Brown', |
| | | age: `12`, |
| | | no: `12`, |
| | | address: 'New York No. 1 Lake ParkNew York No. 1 Lake Park', |
| | | beginTime: new Date().toLocaleString(), |
| | | endTime: new Date().toLocaleString(), |
| | | }, |
| | | ], |
| | | }, |
| | | { |
| | | id: `l2-${index}-2`, |
| | | name: 'John Brown', |
| | | age: `2`, |
| | | no: `${index + 10}`, |
| | | address: 'New York No. 1 Lake ParkNew York No. 1 Lake Park', |
| | | beginTime: new Date().toLocaleString(), |
| | | endTime: new Date().toLocaleString(), |
| | | children: [ |
| | | { |
| | | id: `l3-${index}-2-1`, |
| | | name: 'John Brown', |
| | | age: `21`, |
| | | no: `21`, |
| | | address: 'New York No. 1 Lake ParkNew York No. 1 Lake Park', |
| | | beginTime: new Date().toLocaleString(), |
| | | endTime: new Date().toLocaleString(), |
| | | }, |
| | | { |
| | | id: `l3-${index}-2-2`, |
| | | name: 'John Brown', |
| | | age: `22`, |
| | | no: `22`, |
| | | address: 'New York No. 1 Lake ParkNew York No. 1 Lake Park', |
| | | beginTime: new Date().toLocaleString(), |
| | | endTime: new Date().toLocaleString(), |
| | | }, |
| | | ], |
| | | }, |
| | | ], |
| | | }); |
| | | } |
| | | return arr; |
| | | })(); |
| | | } |
| | | |
| | | export const vxeTableColumns: VxeGridPropTypes.Columns = [ |
| | | { |
| | | title: '序号', |
| | | type: 'seq', |
| | | fixed: 'left', |
| | | width: '50', |
| | | align: 'center', |
| | | }, |
| | | { |
| | | title: '固定列', |
| | | field: 'name', |
| | | width: 150, |
| | | showOverflow: 'tooltip', |
| | | fixed: 'left', |
| | | }, |
| | | { |
| | | title: '自适应列', |
| | | field: 'address', |
| | | }, |
| | | { |
| | | title: '自定义列(自定义导出)', |
| | | field: 'no', |
| | | width: 200, |
| | | showOverflow: 'tooltip', |
| | | align: 'center', |
| | | slots: { |
| | | default: ({ row }) => { |
| | | const text = `自定义${row.no}`; |
| | | return [<div class="text-red-500">{text}</div>]; |
| | | }, |
| | | }, |
| | | exportMethod: ({ row }) => { |
| | | return `自定义${row.no}导出`; |
| | | }, |
| | | }, |
| | | { |
| | | title: '自定义编辑', |
| | | width: 150, |
| | | field: 'name1', |
| | | align: 'center', |
| | | editRender: { |
| | | name: 'AInput', |
| | | placeholder: '请点击输入', |
| | | }, |
| | | }, |
| | | { |
| | | title: '开始时间', |
| | | width: 150, |
| | | field: 'beginTime', |
| | | showOverflow: 'tooltip', |
| | | align: 'center', |
| | | }, |
| | | { |
| | | title: '结束时间', |
| | | width: 150, |
| | | field: 'endTime', |
| | | showOverflow: 'tooltip', |
| | | align: 'center', |
| | | }, |
| | | { |
| | | width: 160, |
| | | title: '操作', |
| | | align: 'center', |
| | | slots: { default: 'action' }, |
| | | fixed: 'right', |
| | | }, |
| | | ]; |
| | | |
| | | export const vxeTableFormSchema: VxeFormItemProps[] = [ |
| | | { |
| | | field: 'field0', |
| | | title: 'field0', |
| | | itemRender: { |
| | | name: 'AInput', |
| | | }, |
| | | span: 6, |
| | | }, |
| | | { |
| | | field: 'field1', |
| | | title: 'field1', |
| | | itemRender: { |
| | | name: 'AApiSelect', |
| | | props: { |
| | | api: optionsListApi, |
| | | resultField: 'list', |
| | | labelField: 'name', |
| | | valueField: 'id', |
| | | }, |
| | | }, |
| | | span: 6, |
| | | }, |
| | | { |
| | | span: 12, |
| | | align: 'right', |
| | | className: '!pr-0', |
| | | itemRender: { |
| | | name: 'AButtonGroup', |
| | | children: [ |
| | | { |
| | | props: { type: 'primary', content: '查询', htmlType: 'submit' }, |
| | | attrs: { class: 'mr-2' }, |
| | | }, |
| | | { props: { type: 'default', htmlType: 'reset', content: '重置' } }, |
| | | ], |
| | | }, |
| | | }, |
| | | ]; |
| | |
| | | <template> |
| | | <PageWrapper title="客户列表" :contentStyle="contentStyle" :class="`${prefixCls}`" dense |
| | | contentFullHeight fixedHeight> |
| | | <PageWrapper title="客户" :contentStyle="contentStyle" :class="`${prefixCls}`" dense contentFullHeight fixedHeight> |
| | | <!-- <template #subTitle></template>--> |
| | | <!-- <template #headerContent>--> |
| | | <!-- <a-button type="primary" @click="$emit('add')">新增</a-button>--> |
| | | <!-- </template>--> |
| | | <template #extra> |
| | | <PopConfirmButton>按钮文本</PopConfirmButton> |
| | | <BasicHelp text="提示"/> |
| | | <BasicHelp :text="['提示1', '提示2']"/> |
| | | <BasicTitle :helpMessage="['提示1', '提示2']">标题</BasicTitle> |
| | | <a-button shape="round" key="1" type="primary">Primary</a-button> |
| | | <Dropdown |
| | | :dropMenuList="getDropMenuList" |
| | | :trigger="['click']" |
| | | placement="bottomLeft" |
| | | overlayClassName="multiple-tabs__dropdown" |
| | | > |
| | | <Icon icon="ion:chevron-down"/> |
| | | </Dropdown> |
| | | <!-- <a-dropdown>--> |
| | | <!-- <template #overlay>--> |
| | | <!-- <a-menu @click="handleMenuClick">--> |
| | | <!-- <a-menu-item key="1">1st item</a-menu-item>--> |
| | | <!-- <a-menu-item key="2">2nd item</a-menu-item>--> |
| | | <!-- <a-menu-item key="3">3rd item</a-menu-item>--> |
| | | <!-- </a-menu>--> |
| | | <!-- </template>--> |
| | | <!-- <a-button>--> |
| | | <!-- Actions--> |
| | | <!-- <DownOutlined />--> |
| | | <!-- </a-button>--> |
| | | <!-- </a-dropdown>--> |
| | | <a-button shape="round" key="1" type="primary" @click="openNewCustomer">新建客户</a-button> |
| | | </template> |
| | | <!-- <template #headerContent>left</template>--> |
| | | <Splitpanes class="default-theme" :push-other-panes="false" style="height: 100%"> |
| | |
| | | </Pane> |
| | | <Pane min-size="50" size="88"> |
| | | <ScrollContainer class="p-8"> |
| | | <!-- <div><a-button class="mr-2" type="primary" shape="round" @click="openModal1"> 新建日程 </a-button></div>--> |
| | | <!-- <div><a-button class="mr-2" type="primary" shape="round" @click="openModal2"> 选择人员 </a-button></div>--> |
| | | <Table></Table> |
| | | </ScrollContainer> |
| | | </Pane> |
| | | </Splitpanes> |
| | | <DrawerForm @register="registerDrawer" @success="handleSuccess"></DrawerForm> |
| | | <NewFollowUp @register="registerNewFollowUp" /> |
| | | <NewSchedule @register="registerNewSchedule" /> |
| | | <PersonnelModal @register="registerPersonnelModal" /> |
| | | <ChangeStatusModal @register="registerChangeStatusModal" /> |
| | | <ReallocateModal @register="registerReallocateModal" /> |
| | | </PageWrapper> |
| | | </template> |
| | | |
| | | <script lang="ts" setup> |
| | | import {PageWrapper} from '@/components/Page'; |
| | | import {computed, onMounted } from 'vue'; |
| | | import {computed, onMounted,onUnmounted} from 'vue'; |
| | | import {useDesign} from "@/hooks/web/useDesign"; |
| | | import {Splitpanes, Pane} from 'splitpanes'; |
| | | import 'splitpanes/dist/splitpanes.css'; |
| | | import LeftNav from './components/LeftNav.vue'; |
| | | import Table from './components/Table.vue'; |
| | | import DrawerForm from './components/DrawerForm.vue'; |
| | | import ScrollContainer from "@/components/Container/src/ScrollContainer.vue"; |
| | | import {BasicHelp, BasicTitle} from '@/components/Basic'; |
| | | import {PopConfirmButton} from '@/components/Button'; |
| | | |
| | | const [registerDrawer, { openDrawer }] = useDrawer(); |
| | | function handleSuccess() { |
| | | Logger.log('提交drawer成功') |
| | | } |
| | | // import {CollapseContainer} from '@/components/Container'; |
| | | // import {Menu, MenuProps} from 'ant-design-vue'; |
| | | // import { DownOutlined } from '@ant-design/icons-vue'; |
| | | import {Dropdown, type DropMenu} from '@/components/Dropdown'; |
| | | import Icon from "@/components/Icon/Icon.vue"; |
| | | import { BasicArrow } from '@/components/Basic'; |
| | | import {useDrawer} from "@/components/Drawer"; |
| | | import {useModal} from "@/components/Modal"; |
| | | import {NewFollowUp} from "@/components/NewFollowUp"; |
| | | import {NewSchedule} from "@/components/NewSchedule"; |
| | | import PersonnelModal from "@/components/NewSchedule/src/PersonnelModal.vue"; |
| | | import ChangeStatusModal from "./components/change-status/index.vue"; |
| | | import ReallocateModal from "./components/reallocate/index.vue"; |
| | | |
| | | const [registerNewFollowUp,{ openModal:openFollowUpModal,setModalProps:setFollowUpModalProps }] = useModal(); |
| | | const [registerNewSchedule, { openModal:openScheduleModal,setModalProps:setScheduleModalProps }] = useModal(); |
| | | const [registerPersonnelModal, { openModal: openPersonnelModal }] = useModal(); |
| | | const [registerChangeStatusModal, { openModal: openChangeStatusModal }] = useModal(); |
| | | const [registerReallocateModal, { openModal: openReallocateModal }] = useModal(); |
| | | |
| | | import EventBus from "@/utils/eventBus"; |
| | | |
| | | |
| | | function openNewCustomer() { |
| | | // eventMitter.emit('openNewCustomer'); |
| | | openDrawer(true, { |
| | | isUpdate: false, |
| | | }); |
| | | |
| | | } |
| | | |
| | | function openModal1() { |
| | | // openModal(true, { |
| | | // // data: 'content2', |
| | | // // info: 'Info', |
| | | // }); |
| | | EventBus.emit('openScheduleModal',{ |
| | | title:'新建任务12', |
| | | content:'新建任务内容12' |
| | | }); |
| | | } |
| | | function openModal2() { |
| | | openPersonnelModal(true, { |
| | | // data: 'content2', |
| | | // info: 'Info', |
| | | }); |
| | | } |
| | | |
| | | onMounted(() => { |
| | | Logger.log('Hello, 客户页'); |
| | | EventBus.on('openScheduleModal', (data) => { |
| | | Logger.log('监听openScheduleModal',data); |
| | | setScheduleModalProps({ |
| | | zIndex: 1001, |
| | | }) |
| | | openScheduleModal(true, { |
| | | // data: 'content2', |
| | | // info: 'Info', |
| | | }); |
| | | }); |
| | | |
| | | EventBus.on('openFollowUpModal', (data) => { |
| | | Logger.log('监听openFollowUpModal',data); |
| | | setFollowUpModalProps({ |
| | | zIndex: 1001, |
| | | }) |
| | | openFollowUpModal(true, { |
| | | // data: 'content2', |
| | | // info: 'Info', |
| | | }); |
| | | }); |
| | | |
| | | EventBus.on('openChangeStatusModal', (data) => { |
| | | Logger.log('监听openChangeStatusModal',data); |
| | | openChangeStatusModal(true, { |
| | | data, |
| | | }); |
| | | }); |
| | | EventBus.on('openReallocateModal', (data) => { |
| | | Logger.log('监听openReallocateModal',data); |
| | | openReallocateModal(true, { |
| | | data, |
| | | }); |
| | | }); |
| | | }); |
| | | const {prefixCls} = useDesign('customer'); |
| | | onUnmounted(() => { |
| | | Logger.log('Goodbye, 线索页'); |
| | | EventBus.off('openScheduleModal',() => { |
| | | Logger.log('取消监听openScheduleModal'); |
| | | }); |
| | | EventBus.off('openFollowUpModal',() => { |
| | | Logger.log('取消监听openFollowUpModal'); |
| | | }); |
| | | EventBus.off('openChangeStatusModal',() => { |
| | | Logger.log('取消监听openChangeStatusModal'); |
| | | }); |
| | | }); |
| | | const {prefixCls} = useDesign('clues'); |
| | | // const AMenu = Menu; |
| | | // const AMenuItem = Menu.Item; |
| | | const contentStyle = { |
| | | borderTop: '1px solid #ddd', |
| | | }; |
| | | |
| | | // const openChange = (openKeys: string[]) => { |
| | | // console.log(666,openKeys); |
| | | // }; |
| | | |
| | | // const handleMenuClick: MenuProps['onClick'] = e => { |
| | | // console.log('click', e); |
| | | // }; |
| | | |
| | | const getDropMenuList = computed(() => { |
| | | const dropMenuList: DropMenu[] = [ |
| | | { |
| | | text: '导入客户', |
| | | event: 'refresh', |
| | | onClick: (e) => { |
| | | console.log('click'); |
| | | }, |
| | | }, |
| | | { |
| | | text: '导入阿里客户', |
| | | event: 'drop', |
| | | onClick: (e) => { |
| | | console.log('click2'); |
| | | }, |
| | | }, |
| | | ]; |
| | | |
| | | return dropMenuList; |
| | | }); |
| | | |
| | | </script> |
| | | |
| | | <style lang="less" scoped> |
| | | @prefix-cls: ~'@{namespace}-customer'; |
| | | @prefix-cls: ~'@{namespace}-clues'; |
| | | .@{prefix-cls} { |
| | | .splitpanes__pane { |
| | | display: flex; |
| | |
| | | align-items: center; |
| | | background-color: var(--component-background-color) |
| | | } |
| | | |
| | | :deep(.ant-page-header) { |
| | | padding: 15px 24px; |
| | | } |
| | | } |
| | | </style> |