飘泊客 10 months ago
commit 2b768b368c

@ -33,3 +33,13 @@ export function updateResource(resourcesDto: resourcesDtoDTO) {
// export function deleteUser(userId: number) { // export function deleteUser(userId: number) {
// return httpClient.delete<ApiResult<void>>(`/system/user/${userId}`) // return httpClient.delete<ApiResult<void>>(`/system/user/${userId}`)
// } // }
/**
*
* @param pageParams
*/
export function messageAccessLogs(pageParams: SysUserPageParam) {
return httpClient.get<ApiResult>('/notify/user-announcement/page', {
params: pageParams
})
}

@ -18,6 +18,7 @@ export type CustomerListQO = {
startTime?: string startTime?: string
// 结束时间 // 结束时间
endTime?: string endTime?: string
clueId?: string
} }
/** /**
* 线record * 线record

@ -0,0 +1,38 @@
@font-face {
font-family: 'iconfont'; /* Project id 4340011 */
src: url('//at.alicdn.com/t/c/font_4340011_rzfq6m1kbn.woff2?t=1700639506016') format('woff2'),
url('//at.alicdn.com/t/c/font_4340011_rzfq6m1kbn.woff?t=1700639506016') format('woff'),
url('//at.alicdn.com/t/c/font_4340011_rzfq6m1kbn.ttf?t=1700639506016') format('truetype');
}
.iconfont {
font-family: 'iconfont' !important;
font-size: 16px;
font-style: normal;
-webkit-font-smoothing: antialiased;
-moz-osx-font-smoothing: grayscale;
}
.icon-xin2:before {
content: '\e647';
}
.icon-xin1:before {
content: '\e600';
}
.icon-xin:before {
content: '\e6c9';
}
.icon-xiaoxi1:before {
content: '\e611';
}
.icon-xiaoxizhongxin:before {
content: '\e7d9';
}
.icon-xiaoxi:before {
content: '\e6c5';
}

Binary file not shown.

After

Width:  |  Height:  |  Size: 13 KiB

@ -0,0 +1,376 @@
<template>
<div class="ms-container">
<div class="top-column">
<div>消息列表</div>
<div class="seeMore" @click="seeMore"></div>
</div>
<div class="item-conent frame-style">
<div v-if="newclueList.length > 0" class="center">
<div v-for="(item, index) in newclueList" :key="index" class="listItem">
<div class="listItemTop">
<div class="type">
{{ item.type === 1 ? '系统公告' : '导出通知' }}{{ item.title }}
</div>
<div class="time">{{ item.createTime }}</div>
</div>
<div class="listItemCenter">
<span ref="contentRef" class="content" :class="{ expanded: item.show }">{{
item.content
}}</span>
<div class="iconContainer" @click="toggleShowAll(item)">
<div v-if="item.show" class="openOrClose">
<span><down-outlined /></span>
</div>
<div v-else class="openOrClose">
<up-outlined />
</div>
</div>
</div>
<div class="listItemBottom">
<a key="list-loadmore-edit" style="margin-right: 8px">{{
item.state === 1 ? '已读' : '确认'
}}</a>
<a
key="list-loadmore-more"
style="border-left: 1px solid rgba(0, 0, 0, 0.06); padding-left: 8px"
@click="positioning(item.messageKey)"
>定位</a
>
</div>
</div>
</div>
<div v-else class="empty">
<a-empty description="暂无数据" :image="zanwu" />
</div>
</div>
<!-- 新消息列表弹出框 -->
<div>
<a-modal
v-model:visible="listVisible"
title="新线索列表"
:mask-closable="false"
:width="900"
@ok="handleOk"
>
<!-- 工具栏 -->
<message-search :loading="tableRef?.loading" @search="searchTable" />
<!-- 底部表格 -->
<pro-table
ref="tableRef"
row-key="userId"
:request="tableRequest"
:columns="columns"
:scroll="{ x: 800 }"
:tool-bar-render="false"
class="protable"
:pagination="{ showQuickJumper: true }"
>
<template #bodyCell="{ column, record }">
<template v-if="column.key === 'clueLabelList'">
<a-tooltip v-if="record.clueLabelList.length > 0">
<template #title
><a-tag
v-for="(item, index) in record.clueLabelList"
:key="index"
class="tagGroupContentItem"
>{{ item }}</a-tag
></template
>
<a-tag v-for="(item, index) in record.clueLabelList" :key="index">{{ item }}</a-tag>
</a-tooltip>
<span v-else>--</span>
</template>
<template v-else-if="column.key === 'remark'">
<a-tooltip v-if="record.remark">
<template #title
><span>{{ record.remark }}</span></template
>
<span>{{ record.remark }}</span>
</a-tooltip>
<span v-else>--</span>
</template>
</template>
</pro-table>
</a-modal>
</div>
</div>
</template>
<script setup lang="ts">
import { ref, watch, onMounted } from 'vue'
import zanwu from '@/assets/images/zanwu.png'
//
import ProTable from '#/table'
import type { ProTableInstanceExpose, TableRequest, ProColumns } from '#/table'
import { mergePageParam } from '@/utils/page-utils'
import { messageAccessLogs } from '@/api/customermanagement/customerList'
import type { CustomerListQO } from '@/api/customermanagement/customerList/types'
import MessageSearch from '@/components/Message/messageSearch.vue'
import type { DistributeTaskManagementPageParam } from '@/api/controlcenterstation/distributionTaskManagement/types'
import router from '@/router'
defineOptions({ name: 'MessagePage' })
interface DataItem {
id: number | undefined
type: number
createTime: string
content: string
messageKey: string
state: number | undefined
title: string
show: boolean
}
const props = defineProps({
newclueList: {
type: Array as () => DataItem[],
required: true,
default: () => []
}
// props...
})
// // props.listVisible visible
// watch(
// () => props.listVisible,
// newValue => {
// listVisible.value = newValue
// console.log(newValue, 'newValue')
// }
// )
const emits = defineEmits<{
(e: 'submit-success'): void
(e: 'click-success', isSuccessful: boolean): void
}>()
//
//
const tableRef = ref<ProTableInstanceExpose>()
//
let searchParams: CustomerListQO = {}
//
const tableRequest: TableRequest = (params, sorter, filter) => {
const pageParam = mergePageParam(params, sorter, filter)
return messageAccessLogs({ ...pageParam, ...searchParams })
}
//
const reloadTable = (resetPageIndex?: boolean) => {
tableRef.value?.actionRef?.reload(resetPageIndex)
}
//
const searchTable = (params: DistributeTaskManagementPageParam) => {
searchParams = params
reloadTable(true) // tableRequest
}
const columns: ProColumns[] = [
{
title: '序号',
width: '80px',
customRender: function ({ index }) {
return `${index + 1}`
}
},
{
title: '标题',
dataIndex: 'title',
width: '120px',
customRender: function ({ record }: any) {
if (record.nid) {
return record.nid
} else if (record.nid === '') {
return '--'
}
}
},
{
title: '类型',
dataIndex: 'type',
width: '100px',
ellipsis: true,
align: 'center',
customRender: function ({ record }: any) {
if (record.type === 1) {
return '系统公告'
} else if (record.type === 2) {
return '导出通知'
}
}
},
{
title: '状态',
dataIndex: 'state',
width: '100px',
ellipsis: true,
align: 'center',
customRender: function ({ record }: any) {
if (record.state === 0) {
return '未读'
} else if (record.state === 1) {
return '已读'
}
}
},
{
title: '描述',
dataIndex: 'content',
ellipsis: true,
align: 'center'
},
{
title: '创建日期',
dataIndex: 'createTime',
width: 150,
align: 'center',
ellipsis: true
}
]
const listVisible = ref<boolean>(false)
const seeMore = () => {
emits('submit-success')
setTimeout(() => {
listVisible.value = true
}, 500) // 0.5 listVisible.value
}
//
const handleOk = (e: MouseEvent) => {
console.log(e)
listVisible.value = false
}
//
const positioning = (messageKey: string) => {
emits('click-success', false)
router.push({ path: '/task/customerlist', query: { clueId: messageKey } }) // /task/customerlist
}
//
const toggleShowAll = (itemShow: DataItem) => {
itemShow.show = !itemShow.show
}
const contentRef = ref<HTMLElement | null>(null)
</script>
<style lang="less" scoped>
.ms-container {
width: 320px;
}
.top-column {
display: flex;
justify-content: space-between;
margin-bottom: 6px;
padding: 10px;
& div:nth-child(1) {
font-size: 14px;
font-weight: 600;
}
& div:nth-child(2) {
font-size: 14px;
color: #1890ff;
cursor: pointer;
}
}
.item-conent {
overflow: auto;
overflow-y: overlay; /* 让滚动条覆盖内容 */
overflow-y: auto;
padding: 0 10px 10px; /* 为滚动条留出空间 */
.item-msg {
border: 1px solid #303133;
border-radius: 4px;
padding: 5px;
margin-bottom: 8px;
}
.iconimg {
width: 13px;
height: auto;
margin-right: 5px;
}
.topImg {
width: 17px;
height: auto;
}
.conent-top {
height: 450.96px;
padding: 0 10px;
}
.conent-bot {
width: 100%;
text-align: center;
height: 25px;
line-height: 25px;
font-size: 14px;
color: #1890ff;
border-top: 1px solid #e0e0e0;
}
.empty {
margin-top: 30px;
}
}
.frame-style {
height: 480px;
}
.listItem {
border-bottom: 1px solid #f0f0f0;
padding: 12px 0;
}
.listItemTop {
display: flex;
justify-content: space-between;
align-items: center;
.type {
font-weight: 700;
width: 130px;
overflow: hidden;
text-overflow: ellipsis;
white-space: normal; /* 允许溢出内容进行换行 */
}
.time {
color: #c3c3c3;
font-size: 12px;
}
}
.listItemCenter {
display: flex;
align-items: end;
color: #767575;
width: 100%;
height: auto;
word-wrap: break-word;
word-break: break-all;
overflow: hidden;
white-space: normal !important;
margin: 5px 0;
font-size: 13px;
}
.iconContainer {
display: inline-block; /* 让容器内的内容水平排列 */
vertical-align: middle; /* 垂直居中对齐 */
}
.content {
white-space: normal; /* 不换行 */
overflow: hidden; /* 超出部分隐藏 */
text-overflow: clip; /* 超出部分裁剪隐藏 */
}
.content.expanded {
white-space: normal; /* 不换行 */
overflow: hidden; /* 超出部分隐藏 */
text-overflow: clip; /* 超出部分裁剪隐藏 */
display: -webkit-box; /* 将元素作为弹性伸缩盒子模型显示 */
-webkit-box-orient: vertical; /* 设置伸缩盒子的子元素垂直排列 */
-webkit-line-clamp: 2; /* 设置显示的行数 */
}
.openOrClose {
display: inline;
margin-left: 4px;
float: right;
}
.listItemBottom {
display: flex;
justify-content: flex-end;
}
</style>

@ -0,0 +1,72 @@
<template>
<a-card :bordered="false" style="margin-bottom: 16px" :body-style="{ paddingBottom: 0 }">
<a-form :model="formModel" :label-col="labelCol">
<a-row :gutter="16">
<a-col :xl="12" :md="12" :sm="24">
<a-form-item label="创建时间">
<a-range-picker
v-model:value="searchTimeValue"
show-time
format="YYYY-MM-DD HH:mm:ss"
style="width: 100%"
:ranges="{
Today: [dayjs().startOf('date'), dayjs()]
}"
/>
</a-form-item>
</a-col>
<a-col :xl="3" :md="3" :sm="12">
<search-actions :loading="props.loading" @search="search" @reset="reset" />
</a-col>
</a-row>
</a-form>
</a-card>
</template>
<script setup lang="ts">
import { Form } from 'ant-design-vue'
import type { DistributeTaskManagementSearch } from '@/api/controlcenterstation/distributionTaskManagement/types'
import dayjs from 'dayjs'
import type { Dayjs } from 'dayjs'
const useForm = Form.useForm
// label
const labelCol = { md: { span: 6 } }
const props = withDefaults(
defineProps<{
loading?: boolean
}>(),
{ loading: false }
)
const emits = defineEmits<{
(e: 'search', params: Record<string, any>): void
}>()
const searchTimeValue = ref<[Dayjs, Dayjs]>()
const formModel = reactive<DistributeTaskManagementSearch>({})
const { resetFields } = useForm(formModel)
const search = () => {
const param = toRaw(formModel)
if (searchTimeValue.value && searchTimeValue.value.length == 2) {
param.startTime = searchTimeValue.value[0].format('YYYY-MM-DD HH:mm:ss')
param.endTime = searchTimeValue.value[1].format('YYYY-MM-DD HH:mm:ss')
} else {
param.startTime = ''
param.endTime = ''
}
emits('search', param)
}
const reset = () => {
//
resetFields()
//
searchTimeValue.value = undefined
search()
}
</script>

@ -1,57 +1,72 @@
// import { useWebSocket, type UseWebSocketReturn } from '@vueuse/core' import { useWebSocket, type UseWebSocketReturn } from '@vueuse/core'
// import { useUserStore } from '@/stores/user-store' import { useUserStore } from '@/stores/user-store'
// import { emitter } from '@/hooks/mitt' import { emitter } from '@/hooks/mitt'
import { message } from 'ant-design-vue'
// let useWebSocketReturn: UseWebSocketReturn<any> | undefined = undefined
// const useAdminWebSocket = () => { let useWebSocketReturn: UseWebSocketReturn<any> | undefined = undefined
// if (useWebSocketReturn && useWebSocketReturn.status.value != 'CLOSED') { //它是一个自定义的Vue hook用于管理WebSocket连接
// return useWebSocketReturn const useAdminWebSocket = () => {
// } //检查是否已经存在WebSocket连接以及连接状态。如果WebSocket连接存在且状态不是已关闭则直接返回现有的WebSocket连接。
if (useWebSocketReturn && useWebSocketReturn.status.value != 'CLOSED') {
// const { accessToken } = useUserStore() return useWebSocketReturn
}
// // ws地址
// const baseUri = import.meta.env.VITE_API_URL const { accessToken } = useUserStore()
// const host = window.location.host console.log(accessToken, 'accessToken')
// const wsUri = `ws://${host}${baseUri}/ws?access_token=${accessToken}`
// ws地址
// useWebSocketReturn = useWebSocket(wsUri, { const baseUri = import.meta.env.VITE_API_URL
// autoReconnect: { const host = window.location.host
// retries: 3, console.log(host, 'host')
// delay: 1000, const wsUri = `ws://${host}${baseUri}/ws?access_token=${accessToken}`
// onFailed() { console.log(wsUri, 'wsUri')
// console.error('Failed to connect WebSocket after 3 retries')
// } //使用useWebSocket函数创建WebSocket连接并配置自动重连和心跳机制
// }, useWebSocketReturn = useWebSocket(wsUri, {
// heartbeat: { autoReconnect: {
// message: '{"type": "ping"}', retries: 3,
// interval: 30000 delay: 1000,
// } onFailed() {
// }) console.error('Failed to connect WebSocket after 3 retries')
}
// watch( },
// () => useWebSocketReturn!.data.value, heartbeat: {
// value => { message: '{"type": "ping"}',
// let event interval: 30000
// let dataMsg }
})
// try {
// dataMsg = JSON.parse(value) //监听WebSocket的数据变化根据接收到的消息类型进行相应的处理并通过emitter发布事件或数据。
// event = dataMsg.type watch(
// // 心跳响应跳过发布 () => useWebSocketReturn!.data.value,
// if (event === 'pong') { value => {
// return let event
// } let dataMsg
// } catch (e) {
// // 纯文本消息 try {
// event = 'plaintext' dataMsg = JSON.parse(value)
// dataMsg = value event = dataMsg.type
// } // 心跳响应跳过发布
// emitter.emit(event, dataMsg) if (event === 'pong') {
// } return
// ) }
} catch (e) {
// return useWebSocketReturn // 纯文本消息
// } event = 'plaintext'
dataMsg = value
// export default useAdminWebSocket }
// emitter.emit(event, dataMsg)
// console.log(dataMsg, 'dataMsg')
// Show alert with the received message
// alert(JSON.stringify(dataMsg.title) + JSON.stringify(dataMsg.content))
message.info(
JSON.stringify(dataMsg.title).slice(1, -1) +''+ JSON.stringify(dataMsg.content).slice(1, -1)
)
}
)
return useWebSocketReturn
}
//将创建的WebSocket连接对象返回给调用者
export default useAdminWebSocket

@ -2,8 +2,32 @@
<span v-if="loading" :class="[$style.action, $style.account]"> <span v-if="loading" :class="[$style.action, $style.account]">
<a-spin size="small" style="margin-left: 8px; margin-right: 8px" /> <a-spin size="small" style="margin-left: 8px; margin-right: 8px" />
</span> </span>
<div v-else style="display: flex">
<div
v-if="userInfoCurrent === 'ROLE_SALESMAN' || userInfoCurrent === 'ROLE_STORE_SALESMAN'"
ref="container"
@mousedown="handleDocumentClick"
>
<a-dropdown :visible="visible" @click="dropdownClick">
<a class="ant-dropdown-link" @click.prevent>
<i class="iconfont icon-xiaoxi1" style="font-size: 20px" />
</a>
<template #overlay>
<a-menu>
<a-menu-item>
<Message
:newclue-list="newclueList"
@mousedown.stop
@submit-success="reloadTable"
@click-success="reloadTable"
/>
</a-menu-item>
</a-menu>
</template>
</a-dropdown>
</div>
<header-dropdown v-else overlay-class-name="avatar-dropdown"> <header-dropdown overlay-class-name="avatar-dropdown">
<span :class="[$style.action, $style.account]"> <span :class="[$style.action, $style.account]">
<!-- <a-avatar size="small" :class="$style.avatar" :src="currentUser.avatar" alt="avatar" /> --> <!-- <a-avatar size="small" :class="$style.avatar" :src="currentUser.avatar" alt="avatar" /> -->
<a-avatar <a-avatar
@ -42,6 +66,7 @@
</a-menu> </a-menu>
</template> </template>
</header-dropdown> </header-dropdown>
</div>
</template> </template>
<script setup lang="ts"> <script setup lang="ts">
@ -49,11 +74,53 @@ import HeaderDropdown from '@/layouts/components/HeaderDropdown'
import type { MenuInfo } from 'ant-design-vue/es/menu/src/interface' import type { MenuInfo } from 'ant-design-vue/es/menu/src/interface'
import { Modal } from 'ant-design-vue' import { Modal } from 'ant-design-vue'
import { logout } from '@/api/auth' import { logout } from '@/api/auth'
import { useUserStore } from '@/stores/user-store' // import { useUserStore } from '@/stores/user-store'
import { loginPath } from '@/config' import { loginPath } from '@/config'
// import { fileAbsoluteUrl } from '@/utils/file-utils' // import { fileAbsoluteUrl } from '@/utils/file-utils'
import { useMultiTabStore } from '@/stores/multitab-store' import { useMultiTabStore } from '@/stores/multitab-store'
import Avatar from '@/assets/images/avatar.png' import Avatar from '@/assets/images/avatar.png'
import Message from '@/components/Message/index.vue'
import { ref, watch, onMounted, onUnmounted } from 'vue'
import { doRequest } from '@/utils/axios/request'
import { messageAccessLogs } from '@/api/customermanagement/customerList'
import useAdminWebSocket from '@/hooks/websocket'
//
import { useUserStore } from '@/stores/user-store'
const { userInfo } = useUserStore()
const userInfoCurrent = ref<string | undefined>('')
onMounted(() => {
userInfoCurrent.value = userInfo?.roleCodes?.toLocaleString()
if (
userInfoCurrent.value === 'ROLE_SALESMAN' ||
userInfoCurrent.value === 'ROLE_STORE_SALESMAN'
) {
useAdminWebSocket()
}
})
const visible = ref(false)
const container = ref(null)
// 线
interface DataItem {
id: number | undefined
type: number
createTime: string
content: string
messageKey: string
state: number | undefined
title: string
show: boolean
}
const newclueList = ref<DataItem[]>([
// {
// id: undefined,
// type: '',
// createTime: '',
// content: ''
// }
])
const multiTabStore = useMultiTabStore() const multiTabStore = useMultiTabStore()
@ -113,6 +180,53 @@ const onMenuClick = (event: MenuInfo) => {
loginOut() loginOut()
} }
} }
//
const getMessageList = () => {
doRequest(
messageAccessLogs({
size: 10,
page: 1
}),
{
onSuccess: (res: any) => {
newclueList.value = res.data.records
console.log(newclueList.value, 'newclueList.value')
newclueList.value.forEach(item => {
item.show = true
})
}
}
)
}
const dropdownClick = async () => {
if (!visible.value) {
await getMessageList()
}
visible.value = !visible.value
}
const handleDocumentClick = (event: MouseEvent) => {
const messageElement = document.querySelector('.message')
if (
visible.value &&
container.value &&
!(container.value as HTMLElement).contains(event.target as Node)
) {
if (!messageElement || !messageElement.contains(event.target as Node)) {
visible.value = false
}
}
}
document.addEventListener('mousedown', handleDocumentClick)
onUnmounted(() => {
document.removeEventListener('mousedown', handleDocumentClick)
})
//
const reloadTable = () => {
visible.value = false
}
</script> </script>
<script lang="ts"> <script lang="ts">

@ -13,6 +13,7 @@ import './styles/index.less'
import App from './App.vue' import App from './App.vue'
import { enableI18n } from '@/config' import { enableI18n } from '@/config'
import { provincesAndCitiesAndAutonomousRegions } from '@/utils/geopolitical-customers' import { provincesAndCitiesAndAutonomousRegions } from '@/utils/geopolitical-customers'
import '@/assets/iconfont.css'
// 声明一个全局变量,将数据赋值给它 // 声明一个全局变量,将数据赋值给它
declare global { declare global {

@ -0,0 +1,69 @@
<template>
<div>
<dict-select
v-model:value="formModel.httpStatus"
style="display: none"
dict-code="user_status"
allow-clear
placeholder="请选择"
/>
</div>
</template>
<script setup lang="ts">
import { Form } from 'ant-design-vue'
import dayjs from 'dayjs'
import type { Dayjs } from 'dayjs'
import type { CustomerListSearch } from '@/api/customermanagement/customerList/types'
const useForm = Form.useForm
// label
const labelCol = { md: { span: 8 } }
const props = withDefaults(
defineProps<{
loading?: boolean
}>(),
{ loading: false }
)
const emits = defineEmits<{
(e: 'search', params: Record<string, any>): void
}>()
const searchTimeValue = ref<[Dayjs, Dayjs]>()
const formModel = reactive<CustomerListSearch>({
clueLabelName: '',
//线
userId: undefined,
//
httpStatus: undefined,
//
ip: '',
//
nid: ''
})
const { resetFields } = useForm(formModel)
const search = () => {
const param = toRaw(formModel)
if (searchTimeValue.value && searchTimeValue.value.length == 2) {
param.startTime = searchTimeValue.value[0].format('YYYY-MM-DD HH:mm:ss')
param.endTime = searchTimeValue.value[1].format('YYYY-MM-DD HH:mm:ss')
} else {
param.startTime = ''
param.endTime = ''
}
emits('search', param)
}
const reset = () => {
//
resetFields()
//
searchTimeValue.value = undefined
search()
}
</script>

@ -8,12 +8,15 @@
<iframe :id="id" ref="iframeRef" :src="url" class="iframe" @load="hideLoading" /> <iframe :id="id" ref="iframeRef" :src="url" class="iframe" @load="hideLoading" />
</a-spin> --> </a-spin> -->
<!-- 工具栏 -->
<customer-list-search :loading="tableRef?.loading" @search="searchTable" />
<div class="homeContent"> <div class="homeContent">
<div class="bullshit">努力开发中敬请期待...</div> <div class="bullshit">努力开发中敬请期待...</div>
</div> </div>
</template> </template>
<script setup lang="ts"> <script setup lang="ts">
import CustomerListSearch from '@/views/basic/iframe/iframeSearch.vue'
// //
defineOptions({ name: 'IframeView' }) defineOptions({ name: 'IframeView' })

@ -52,6 +52,12 @@
</a-tooltip> </a-tooltip>
<span v-else>--</span> <span v-else>--</span>
</template> </template>
<!-- <template v-else-if="column.key === 'index'">
<span>
<i class="iconfont icon-xin" style="font-size: 18px; margin-right: 8px; color: red"></i>
{{ index + 1 }}
</span>
</template> -->
</template> </template>
</pro-table> </pro-table>
<!-- 详情弹窗 --> <!-- 详情弹窗 -->
@ -61,7 +67,7 @@
</template> </template>
<script setup lang="ts"> <script setup lang="ts">
import { ref } from 'vue' import { ref, onMounted } from 'vue'
// //
// import { UserOutlined, DownOutlined } from '@ant-design/icons-vue' // import { UserOutlined, DownOutlined } from '@ant-design/icons-vue'
// import type { MenuProps } from 'ant-design-vue' // import type { MenuProps } from 'ant-design-vue'
@ -80,9 +86,21 @@ import { pageAccessLogs } from '@/api/customermanagement/customerList'
import CustomerListSearch from '@/views/customermanagement/customerList/customerListSearch.vue' import CustomerListSearch from '@/views/customermanagement/customerList/customerListSearch.vue'
import CustomerListViewModal from '@/views/customermanagement/customerList/customerListModal.vue' import CustomerListViewModal from '@/views/customermanagement/customerList/customerListModal.vue'
import CustomerListEditModal from '@/views/customermanagement/customerList/customerListEditModal.vue' import CustomerListEditModal from '@/views/customermanagement/customerList/customerListEditModal.vue'
import { useRoute } from 'vue-router'
// import useAdminWebSocket from '@/hooks/websocket'
// //
// import { doRequest } from '@/utils/axios/request' // import { doRequest } from '@/utils/axios/request'
const route = useRoute()
onMounted(() => {
const customerId = route.query.clueId as string // 使
if (customerId) {
searchTable({ clueId: customerId })
}
// useAdminWebSocket()
})
defineOptions({ name: 'CustomerList' }) defineOptions({ name: 'CustomerList' })
// //
@ -141,9 +159,32 @@ const handleEdit = (record: CustomerListRecord, tabIndex: string) => {
const columns: ProColumns[] = [ const columns: ProColumns[] = [
{ {
title: '序号', title: '序号',
dataIndex: 'index',
width: '80px', width: '80px',
customRender: function ({ index }) { customRender: function ({ index, record }: { index: number; record: any }) {
return `${index + 1}` if (record.isNewClue === true) {
return {
children: [
h('span', [
h('i', {
style: 'color: red; margin-right: 4px;',
class: 'iconfont icon-xin'
}),
`${index + 1}`
])
]
}
} else {
return {
children: h(
'span',
{
style: 'margin-left: 20px;'
},
`${index + 1}`
)
}
}
} }
}, },
{ {

@ -80,6 +80,7 @@ import { projectTitle, projectDesc, enableLoginCaptcha } from '@/config'
import { SliderCaptcha as LoginCaptcha } from '@/components/Captcha' import { SliderCaptcha as LoginCaptcha } from '@/components/Captcha'
import { useI18n } from 'vue-i18n' import { useI18n } from 'vue-i18n'
import { getCodeData } from '@/api/auth' import { getCodeData } from '@/api/auth'
// import useAdminWebSocket from '@/hooks/websocket'
const { t } = useI18n() const { t } = useI18n()
@ -171,6 +172,26 @@ function handleSubmit(captchaId?: string) {
store(res) store(res)
const nextPath = (router.currentRoute.value.query.redirect as string) || '/' const nextPath = (router.currentRoute.value.query.redirect as string) || '/'
router.push(nextPath) router.push(nextPath)
// WebSocket
// const webSocket =
// useAdminWebSocket()
// // WebSocket
// if (webSocket && webSocket.status.value === 'OPEN') {
// //
// const messageData = {
// type: 'chatMessage',
// content: 'Hello, WebSocket!'
// }
// //
// webSocket.send(JSON.stringify(messageData))
// //
// console.log('Sent message:', JSON.stringify(messageData))
// } else {
// console.error('WebSocket connection is not open')
// }
}) })
.catch(err => { .catch(err => {
// console.log(accountLoginFormRef.value, 'accountLoginFormRef') // console.log(accountLoginFormRef.value, 'accountLoginFormRef')

@ -102,6 +102,8 @@ declare module '@vue/runtime-core' {
LovModal: typeof import('./../src/components/Lov/LovModal.vue')['default'] LovModal: typeof import('./../src/components/Lov/LovModal.vue')['default']
LovSearch: typeof import('./../src/components/Lov/LovSearch.vue')['default'] LovSearch: typeof import('./../src/components/Lov/LovSearch.vue')['default']
MailOutlined: typeof import('@ant-design/icons-vue')['MailOutlined'] MailOutlined: typeof import('@ant-design/icons-vue')['MailOutlined']
Message: typeof import('./../src/components/Message/index.vue')['default']
MessageSearch: typeof import('./../src/components/Message/messageSearch.vue')['default']
MinusCircleOutlined: typeof import('@ant-design/icons-vue')['MinusCircleOutlined'] MinusCircleOutlined: typeof import('@ant-design/icons-vue')['MinusCircleOutlined']
MobileOutlined: typeof import('@ant-design/icons-vue')['MobileOutlined'] MobileOutlined: typeof import('@ant-design/icons-vue')['MobileOutlined']
OperationGroup: typeof import('./../src/components/Operation/OperationGroup.vue')['default'] OperationGroup: typeof import('./../src/components/Operation/OperationGroup.vue')['default']

@ -26,14 +26,14 @@ import { antdvStyleDeps } from './src/utils/resolvers'
//jt //jt
// export const serverAddress = 'http://172.18.1.8:8000' // export const serverAddress = 'http://172.18.1.8:8000'
//ts //ts
// export const serverAddress = 'http://172.18.0.228:8000' export const serverAddress = 'http://172.18.0.228:8000'
//测试 //测试
// export const serverAddress = 'http://39.100.77.21:8000' // export const serverAddress = 'http://39.100.77.21:8000'
//线上ip //线上ip
// export const serverAddress = 'http://175.27.212.74:80' // export const serverAddress = 'http://175.27.212.74:80'
//线上域名,现在用这个 //线上域名,现在用这个
export const serverAddress = 'https://byffp.top' // export const serverAddress = 'https://byffp.top'
// export const serverAddress = 'http://8.130.96.163:8100' // export const serverAddress = 'http://8.130.96.163:8100'
// https://vitejs.dev/config/ // https://vitejs.dev/config/
// export const serverAddress = process.env.VUE_APP_BASE_API // export const serverAddress = process.env.VUE_APP_BASE_API
@ -45,7 +45,7 @@ export default defineConfig({
'^/api': { '^/api': {
target: serverAddress, target: serverAddress,
changeOrigin: true, changeOrigin: true,
// ws: true, ws: true,
rewrite: path => { rewrite: path => {
return path.replace(/^\/api/, '') return path.replace(/^\/api/, '')
} }

Loading…
Cancel
Save