682 lines
30 KiB
TypeScript
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

import LeftSelectTree from "@/components/leftSelectTree/leftSelectTree";
import { handleGetServerpartDDL } from "@/components/leftSelectTree/service";
import { ActionType, FormInstance, ProCard, ProForm, ProFormList, ProFormSelect, ProFormSwitch, ProFormText, ProFormTextArea, ProTable } from "@ant-design/pro-components";
import { Button, Col, message, Modal, Popconfirm, Row, Space, Image, Drawer } from "antd";
import moment from "moment";
import { useRef, useState } from "react";
import { connect } from "umi";
import { handleAddTemplates, handleDeleteTemplates, handleGetQuestionList, handleGetTemplatesList, handleUpdateTemplates, handleUploadFile } from "./service";
import { handleGetExamineTypeTreeList } from "../index/service";
import QRCode from 'qrcode';
import { base64ToFile } from "@/utils/publicMethods";
import RecordDetail from "../record/components/recordDetail";
const examineModal: React.FC<{ currentUser: any }> = (props) => {
const { currentUser } = props
const actionRef = useRef<ActionType>();
const formRef = useRef<FormInstance>();
const modalActionRef = useRef<ActionType>();
const modalFormRef = useRef<FormInstance>();
// 弹出框的表单实例
const modalRef = useRef<FormInstance>()
// 树相关的属性和方法
const [selectedId, setSelectedId] = useState<string>()
const [collapsible, setCollapsible] = useState<boolean>(false)
// 显示新增点位的悬浮框
const [showPlaceModal, setShowPlaceModal] = useState<boolean>(false)
// 显示详情
const [showDetail, handleShowDetail] = useState<boolean>(false)
// 当前点击选中的问题行
const [currentRow, setCurrentRow] = useState<any>()
// 服务区的枚举
const [serviceObj, setServiceObj] = useState<any>()
// 生成的二维码的初始
const [qrCodeUrl, setQrCodeUrl] = useState<string>()
// 选择问题的悬浮框
const [selectQuestionModal, setSelectQuestionModal] = useState<boolean>(false)
// 选择的问题列表 详情
const [selectedQuestionDetail, setSelectedQuestionDetail] = useState<any>()
// 选择的问题列表的id
const [selectedQuestionId, setSelectedQuestionId] = useState<any>()
// 显示的附件数据
const [showImgList, setShowImgList] = useState<string[]>([])
// 预览图片
const [imagePreviewVisible, setImagePreviewVisible] = useState<boolean>(false)
// 预览的索引
const [previewIndex, setPreviewIndex] = useState<number>(0)
const [columnsStateMap, setColumnsStateMap] = useState<any>({
updatedAt: { show: false },
createdAt: { show: false },
operator: { show: false },
})
const columns: any = [
{
title: <div style={{ textAlign: 'center' }}></div>,
dataIndex: "serverPartName",
hideInSearch: true,
width: 150,
ellipsis: true
},
{
title: <div style={{ textAlign: 'center' }}></div>,
dataIndex: "title",
hideInSearch: true,
width: 200,
ellipsis: true
},
{
title: <div style={{ textAlign: 'center' }}></div>,
dataIndex: "questions",
hideInSearch: true,
width: 400,
ellipsis: true,
render: (_, record) => {
let questionStr: string = ""
if (record?.questionnaireTemplateQuestions && record?.questionnaireTemplateQuestions.length > 0) {
record?.questionnaireTemplateQuestions.forEach((item: any, index: number) => {
let options: string = ''
if (item.question.options && item.question.options.length > 0) {
item.question.options.forEach((subItem: any, subIndex: number) => {
options += `${subIndex > 0 ? '' : ''}选项${subIndex + 1}${subItem.text}`
})
}
questionStr += `${index > 0 ? '' : ''}问题${index + 1}${item.question.title}${options}`
})
}
return questionStr || ''
// return record?.questions && record?.questions.length > 0 ? JSON.stringify(record?.questions) : ''
}
},
{
title: <div style={{ textAlign: 'center' }}></div>,
dataIndex: "qrUrl",
hideInSearch: true,
align: 'center',
width: 150,
ellipsis: true,
render: (_, record) => {
return record?.qrUrl ? <Button type="primary" onClick={() => {
setShowImgList([record?.qrUrl])
setImagePreviewVisible(true)
}}></Button> : "-"
}
},
{
title: <div style={{ textAlign: 'center' }}></div>,
dataIndex: "status",
hideInSearch: true,
align: 'center',
width: 100,
ellipsis: true,
render: (_, record) => {
return record?.status ? '有效' : '无效'
}
},
{
title: <div style={{ textAlign: 'center' }}></div>,
dataIndex: "description",
hideInSearch: true,
width: 200,
ellipsis: true
},
{
title: <div style={{ textAlign: 'center' }}></div>,
dataIndex: "updatedAt",
hideInSearch: true,
align: 'center',
width: 150,
ellipsis: true,
render: (_, record) => {
return record?.updatedAt ? moment(record?.updatedAt).format('YYYY-MM-DD HH:mm:ss') : ''
}
},
{
title: <div style={{ textAlign: 'center' }}></div>,
dataIndex: "createdAt",
hideInSearch: true,
align: 'center',
width: 150,
ellipsis: true,
render: (_, record) => {
return record?.createdAt ? moment(record?.createdAt).format('YYYY-MM-DD HH:mm:ss') : ''
}
},
{
title: <div style={{ textAlign: 'center' }}></div>,
dataIndex: "operator",
hideInSearch: true,
align: 'center',
width: 100,
ellipsis: true,
},
{
title: '操作',
dataIndex: 'option',
align: 'center',
hideInSearch: true,
fixed: "right",
width: 120,
render: (_: any, record: any) => {
return <Space>
<a onClick={() => {
console.log('record', record);
setCurrentRow(record)
setShowPlaceModal(true)
}}></a>
<a onClick={() => {
setCurrentRow(record)
handleShowDetail(true)
}}></a>
<Popconfirm
title={"确认删除?"}
onConfirm={async () => {
deleteQuestion(record?.id)
}}
>
<a></a>
</Popconfirm>
</Space>
}
}
]
// 弹出框里面的
const modalColumns: any = [
{
title: "问题分类",
dataIndex: "id",
hideInTable: true,
valueType: 'treeSelect',
request: async () => {
const data = await handleGetExamineTypeTreeList()
console.log('data', data);
return data && data.length > 0 ? data.map(item => ({
title: item.name,
value: item.id,
children: item.children?.map((child: any) => ({
title: child.name,
value: child.id,
children: child.children || []
})) || []
})) : []
},
fieldProps: {
multiple: false,
treeDefaultExpandAll: true,
showSearch: true,
treeNodeFilterProp: 'title',
placeholder: '请选择问题分类'
}
},
{
title: "考核内容",
dataIndex: "title",
width: 200,
ellipsis: true,
hideInSearch: true
},
{
title: "考核选项",
dataIndex: "options",
width: 500,
ellipsis: true,
hideInSearch: true,
render: (_, record) => {
let str: string = ''
if (record.options && record?.options.length > 0) {
record.options.forEach((item: any, index: number) => {
str += `${index > 0 ? '' : ''}选项${index + 1}${item.text}`
})
}
return str || ''
// return record?.options && record?.options.length > 0 ? JSON.stringify(record?.options) : ""
}
}
]
// 删除模版
const deleteQuestion = async (id: number) => {
const data = await handleDeleteTemplates({ id: id })
if (data.code === 200) {
message.success(data.message)
actionRef.current?.reload()
}
}
return (
<div style={{ backgroundColor: '#fff', display: 'flex' }}>
{/* <LeftSelectTree setSelectedId={setSelectedId} setCollapsible={setCollapsible} collapsible={collapsible} currentUser={currentUser} /> */}
<div style={{
// width: !collapsible ? 'calc(100% - 300px)' : 'calc(100% - 60px)',
width: "100%",
paddingTop: 0,
paddingBottom: 0,
paddingRight: 0
}}>
<ProTable
actionRef={actionRef}
formRef={formRef}
columns={columns}
bordered
expandable={{
expandRowByClick: true
}}
scroll={{ x: "100%", y: 'calc(100vh - 400px)' }}
headerTitle={<span style={{ color: "#1890ff", fontSize: 14, fontWeight: 600 }}></span>}
search={{ span: 6 }}
request={async () => {
const req: any = {
}
const data = await handleGetTemplatesList()
if (data && data.length > 0) {
return { data, success: true }
}
return { data: [], success: true }
}}
toolbar={{
actions: [
<Button type="primary" onClick={(e) => {
setShowPlaceModal(true)
}}>
</Button>
]
}}
columnsState={{
value: columnsStateMap,
onChange: setColumnsStateMap,
}}
>
</ProTable>
{
showImgList && showImgList.length > 0 && <div style={{ display: 'none' }}>
<Image.PreviewGroup
preview={{
visible: imagePreviewVisible,
onVisibleChange: vis => {
setImagePreviewVisible(vis)
},
current: previewIndex
}}>
{
showImgList.map((n) =>
<Image src={n} key={n} />
)
}
</Image.PreviewGroup>
</div>
}
<Modal
width={1200}
title={`${currentRow?.id ? '编辑' : '创建'}点位`}
open={showPlaceModal}
destroyOnClose
onOk={() => {
modalRef.current?.validateFields().then(async (res) => {
console.log('res', res);
console.log('currentRow', currentRow);
let req = {}
let data = {}
if (currentRow?.id) {
let questions: any = []
if (selectedQuestionDetail && selectedQuestionDetail.length > 0) {
selectedQuestionDetail.forEach((item) => {
questions.push({
questionId: item.id,
isRequired: item.required,
sortOrder: item.sortOrder
})
})
} else {
// 判断是否有改动 一样 说明没改动 那么把老的拿进去就行
if (currentRow?.questionnaireTemplateQuestions.length === res.questions.length) {
if (currentRow?.questionnaireTemplateQuestions && currentRow?.questionnaireTemplateQuestions.length > 0) {
currentRow?.questionnaireTemplateQuestions.forEach((item) => {
questions.push({
questionId: item.question.id,
isRequired: item.question.required,
sortOrder: item.question.sortOrder
})
})
}
} else {
// 不一样 说明有删除 不然走的是第一个
if (res.questions && res.questions.length > 0) {
res.questions.forEach((item) => {
questions.push({
questionId: item.id,
isRequired: item.required,
sortOrder: item.sortOrder
})
})
}
}
}
req = {
...currentRow,
title: res.title,
serverPartName: serviceObj ? serviceObj[res.serverPartId] : "",
serverPartId: res.serverPartId,
questions: questions && questions.length > 0 ? questions : "",
operator: currentUser?.operator,
status: res.status,
description: res.description
}
data = await handleUpdateTemplates(req)
} else {
let questions: any = []
if (selectedQuestionDetail && selectedQuestionDetail.length > 0) {
selectedQuestionDetail.forEach((item) => {
questions.push({
questionId: item.id,
isRequired: item.required,
sortOrder: item.sortOrder
})
})
}
req = {
title: res.title,
placeName: "",
placeId: 0,
serverPartName: serviceObj ? serviceObj[res.serverPartId] : "",
serverPartId: res.serverPartId,
// qrUrl: "",
questions: questions && questions.length > 0 ? questions : "",
operator: currentUser?.operator,
status: res.status,
description: res.description
}
data = await handleAddTemplates(req)
console.log('datadsadsa1', data.data);
const myQRCodeDataUrl = await QRCode.toDataURL(`pages/walkAroundManager/index?id=${data.data.id}`);
const file = base64ToFile(myQRCodeDataUrl, `wenjuan${data.data.id}.png`);
console.log('file', file);
const formData = new FormData();
formData.append("file", file, `wenjuan${data.data.id}.png`); // 确保文件名也传递
const fileData = await handleUploadFile(formData)
console.log('fileData', fileData);
let imgUrl: string = `https://es.robot-z.cn/${fileData.data.path}`
await handleUpdateTemplates({
...data.data,
qrUrl: imgUrl
})
setQrCodeUrl(imgUrl)
// setQrCodeUrl(myQRCodeDataUrl)
}
console.log('datadsadsa', data);
if (data.code === 200) {
modalRef.current?.resetFields()
message.success(data.message)
setShowPlaceModal(false)
actionRef.current?.reload()
setCurrentRow(undefined)
} else {
message.error(data.message)
}
})
}}
onCancel={() => {
modalRef.current?.resetFields()
setShowPlaceModal(false)
setCurrentRow(undefined)
setQrCodeUrl(undefined)
}}
>
<ProForm formRef={modalRef} submitter={false} request={() => {
console.log('currentRow', currentRow);
let questionsList: any = []
let keyList: any = []
if (currentRow?.questionnaireTemplateQuestions && currentRow?.questionnaireTemplateQuestions.length > 0) {
console.log('1');
currentRow?.questionnaireTemplateQuestions.forEach((item) => {
console.log('2');
if (item.question) {
let obj = JSON.parse(JSON.stringify(item.question))
let str: string = ''
if (obj.options && obj?.options.length > 0) {
obj.options.forEach((subItem: any, index: number) => {
str += `${index > 0 ? '' : ''}选项${index + 1}${subItem.text}`
})
}
obj.text = obj.title
obj.mark = JSON.stringify(obj.options)
obj.showText = str
keyList.push(obj.id)
questionsList.push(obj)
}
})
}
// setSelectedQuestionDetail
setSelectedQuestionId(keyList)
return {
...currentRow,
serverPartId: currentRow.serverPartId.toString(),
questions: questionsList
}
}}>
<Row gutter={8}>
<Col span={8}>
<ProFormSelect
label={"服务区名"}
name={"serverPartId"}
request={async () => {
const req = {
ProvinceCode: currentUser?.provinceCode,
StatisticsType: 1000
}
const data = await handleGetServerpartDDL(req)
let obj: any = {}
if (data && data.length > 0) {
data.forEach((item) => {
obj[item.value] = item.label
})
}
setServiceObj(obj)
return data
}}
fieldProps={{
showSearch: true,
}}
rules={[{
required: true,
message: "请选择服务区!"
}]}
/>
</Col>
<Col span={8}>
<ProFormText
label={"点位名称"}
name={"title"}
rules={[{
required: true,
message: "请输入点位名称!"
}]}
/>
</Col>
<Col span={8}>
<ProFormSwitch
label={"有效状态"}
name={"status"}
initialValue={currentRow?.id ? currentRow.status : true}
/>
</Col>
<Col span={20}>
<ProFormList
name="questions"
label="考核列表"
initialValue={[]}
creatorButtonProps={{
position: 'bottom',
creatorButtonText: '添加选项',
style: { display: 'none' },
onClick: (e) => {
console.log('e', e);
}
}}
copyIconProps={false}
style={{ width: '100%' }}
itemContainerStyle={{ width: '100%' }}
itemRender={({ listDom, action }, { record, index }) => (
<div style={{ width: '100%', display: 'flex', alignItems: 'flex-start', marginBottom: '10px' }}>
<div style={{ flex: 1, width: '100%' }}>{listDom}</div>
<div style={{ marginLeft: '8px', marginTop: '30px' }}>{action}</div>
</div>
)}
>
<Row gutter={6} style={{ width: '100%', margin: 0 }}>
<Col span={8}>
<ProFormTextArea
name="text"
label="考核内容"
fieldProps={{
style: { width: '100%' }
}}
/>
</Col>
<Col span={16}>
<ProFormTextArea
name="showText"
label="考核标准"
/>
</Col>
</Row>
</ProFormList>
</Col>
<Col span={4}>
<Button type={"primary"} onClick={() => {
setSelectQuestionModal(true)
}}></Button>
</Col>
<Col span={24}>
<ProFormTextArea
label={"备注说明"}
name={"description"}
/>
</Col>
<Col span={24}>
<ProFormTextArea
label={"二维码URL"}
name={"qrUrl"}
/>
</Col>
<Col span={24}>
{
qrCodeUrl || currentRow?.qrUrl ?
<img style={{ width: "150px", height: "150px" }} src={qrCodeUrl || currentRow?.qrUrl} /> : ""
}
</Col>
</Row>
</ProForm>
</Modal>
<Modal
width={1400}
title={`点位`}
open={selectQuestionModal}
destroyOnClose
onOk={() => {
console.log('selectedQuestionDetail', selectedQuestionDetail);
// 显示的问题列表
let showQuestion: any = []
if (selectedQuestionDetail && selectedQuestionDetail.length > 0) {
selectedQuestionDetail.forEach((item) => {
let str: string = ''
if (item.options && item?.options.length > 0) {
item.options.forEach((item: any, index: number) => {
str += `${index > 0 ? '' : ''}选项${index + 1}${item.text}`
})
}
showQuestion.push({ text: item.title, showText: str, mark: item.options ? JSON.stringify(item.options) : "" })
})
}
modalRef.current?.setFieldsValue({
questions: showQuestion
})
setSelectQuestionModal(false)
}}
onCancel={() => {
setSelectQuestionModal(false)
}}
>
<ProTable
actionRef={modalActionRef}
formRef={modalFormRef}
columns={modalColumns}
rowKey={"id"}
scroll={{ y: 'calc(100vh - 500px)' }}
request={async (params) => {
console.log('查询参数:', params);
const req: any = {
categoryId: params.id
}
const data = await handleGetQuestionList(req)
if (data && data.length > 0) {
return { data, success: true }
}
return { data: [], success: true }
}}
rowSelection={{
type: "checkbox",
defaultSelectedRowKeys: selectedQuestionId,
onChange: (selectedRowKeys, selectedRows) => {
setSelectedQuestionDetail(selectedRows)
setSelectedQuestionId(selectedRowKeys)
}
}}
/>
</Modal>
</div>
<Drawer
title={false}
closeIcon={false}
onClose={() => {
handleShowDetail(false)
}}
open={showDetail}
destroyOnClose
width={'60%'}
>
<RecordDetail parentRow={currentRow} show={showDetail} detailType={'modal'} />
</Drawer>
</div >
)
}
export default connect(({ user }: ConnectState) => ({
currentUser: user.data
}))(examineModal);