| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792 |
- import Taro, { Component } from '@tarojs/taro'
- import { View, Input, Picker, Label, Button, } from '@tarojs/components'
- import { Loading } from '@components'
- import { connect } from '@tarojs/redux'
- import * as actions from '@actions/report'
- import { getWindowHeight } from '@utils/style'
- import ImagePicker from '../../components/imagePicker'
- import RuiEditor from '../../components/editor'
- import './reportdetail.scss'
- @connect(state => state.home, { ...actions, })
- class ReportDetail extends Component {
- config = {
- navigationBarTitleText: '报告撰写'
- }
- state = {
- selector: [
- { name: "文本项", type: "text" },
- { name: "日期项", type: "date" },
- { name: "起止时间", type: "dateRange" },
- ],
- visible: "",
- data: {},
- metadata: [],
- chapterType: [
- { title: "立项背景与意义", key: "BACKGROUND", keywords: ['必要性'] },
- { title: "国内外研究现状与发展趋势", key: "RESEARCH_STATUS", keywords: ['研究现状', '发展趋势'] },
- { title: "项目主要研究内容", key: "RESEARCH", keywords: ['技术特点', '技术研究', '实际应用'] },
- { title: "关键技术与创新点", key: "INNOVATION", keywords: ['关键技术', '创新点'] },
- { title: "拟解决的关键问题", key: "SOLVE_PROBLEM", keywords: ['解决的问题', '解决的关键问题'] },
- { title: "实施方案及进度安排", key: "SOLUTION", keywords: ['实施方案'] },
- { title: "经费预算", key: "BUDGET", keywords: [] },
- { title: "经济及社会效益分析", key: "BENEFIT_ANALYSIS", keywords: ['经济效益', '社会效益', '经济效益分析', '社会效益分析'] },
- { title: "项目风险分析和对策", key: "RISK", keywords: ['风险分析', '风险对策'] },
- { title: "自定义章节", key: "USER_DEFINED", keywords: [] },
- ],
- chapters: [],
- aeList: [],
- name: "",
- newvb: false,
- popup: false,
- template: false,
- name: '',
- tags: [],
- }
- componentDidMount() {
- this.getData()
- this.getQuery()
- }
- componentWillUnmount() {
- }
- // 详情接口
- getData() {
- this.setState({ loading: true })
- let payload = {
- id: this.$router.params.id,
- }
- this.props.reportDetail(payload).then((data) => {
- this.setState({
- loading: false,
- data: data,
- metadata: data.metadata,
- chapters: data.chapters,
- })
- }).catch(() => {
- this.setState({ loading: false })
- })
- }
- // 获取企业列表
- getQuery() {
- let payload = {
- name: "",
- size: 99,
- }
- this.props.query(payload).then((data) => {
- this.setState({
- aeList: data,
- })
- }).catch(() => {
- })
- }
- // Al生成
- getGenerate(title, i) {
- const { data } = this.state
- let payload = {
- chapterTitle: title,
- keywords: data.keywords,
- projectName: data.reportName,
- }
- Taro.showLoading({
- title: 'AI正在撰写章节内容,请稍等…',
- mask: true,
- })
- this.props.generate(payload).then((res) => {
- Taro.hideLoading()
- const chaplist = this.state.data.chapters
- chaplist.forEach(function (item, index) {
- if (index == i) {
- item.content = res
- }
- })
- this.setState({
- chapters: chaplist
- })
- }).catch(() => {
- Taro.hideLoading()
- })
- }
- // 添加新项
- onChange = e => {
- this.setState({
- type: this.state.selector[e.detail.value].type,
- inputName: e.detail.value == 2 ? "起止时间" : undefined,
- visible: "add"
- })
- }
- // 阿拉伯数字转中文
- numberToChinese(num) {
- var arr1 = new Array('零', '一', '二', '三', '四', '五', '六', '七', '八', '九');
- var arr2 = new Array('', '十', '百', '千', '万', '十', '百', '千', '亿', '十', '百', '千', '万', '十', '百', '千', '亿');//可继续追加更高位转换值
- if (!num || isNaN(num)) {
- return "零";
- }
- var english = num.toString().split("");
- var result = "";
- for (var i = 0; i < english.length; i++) {
- var des_i = english.length - 1 - i;//倒序排列设值
- result = arr2[i] + result;
- var arr1_index = english[des_i];
- result = arr1[arr1_index] + result;
- }
- //将【零千、零百】换成【零】 【十零】换成【十】
- result = result.replace(/零(千|百|十)/g, '零').replace(/十零/g, '十');
- //合并中间多个零为一个零
- result = result.replace(/零+/g, '零');
- //将【零亿】换成【亿】【零万】换成【万】
- result = result.replace(/零亿/g, '亿').replace(/零万/g, '万');
- //将【亿万】换成【亿】
- result = result.replace(/亿万/g, '亿');
- //移除末尾的零
- result = result.replace(/零+$/, '');
- //将【零一十】换成【零十】
- //result = result.replace(/零一十/g, '零十');//貌似正规读法是零一十
- //将【一十】换成【十】
- result = result.replace(/^一十/g, '十');
- return result;
- }
- // 字符串拼接
- getTitleWithChineseNum(index, title) {
- return this.numberToChinese(index + 1) + '、' + title
- }
- // 章节添加
- onChapterChange = e => {
- let list = this.state.chapters
- let obj = this.state.chapterType[e.detail.value]
- let data = {
- chapterType: obj.key,
- content: "",
- fullTitle: this.getTitleWithChineseNum(list.length, obj.title),
- keywords: obj.keywords,
- title: obj.title,
- }
- list.push(data)
- this.setState({
- chapters: list
- })
- }
- // 选中关联企业
- onAeChange = e => {
- const { aeList } = this.state
- let obj = aeList[e.detail.value]
- let list = this.state.data
- list.companyName = obj.name
- list.companyId = obj.id
- this.setState({
- data: list,
- })
- }
- // 企业添加
- onAeCancel = () => {
- this.setState({
- name: "",
- newvb: false,
- })
- }
- // 企业添加
- onAeOk = () => {
- if (!this.state.name) {
- Taro.showToast({
- title: "请输入新企业名称",
- icon: 'none'
- })
- return
- }
- const payload = {
- name: this.state.name,
- }
- this.props.company(payload).then((data) => {
- let obj = this.state.data
- obj.companyName = data.name
- obj.companyId = data.id
- this.setState({
- data: obj,
- newvb: false,
- })
- }).catch(() => {
- })
- }
- // 添加新项弹窗
- onCancel = () => {
- this.setState({
- inputName: undefined,
- inputText: undefined,
- dateSel: undefined,
- dataStart: undefined,
- dataEnd: undefined,
- indx: undefined,
- type: "",
- visible: "",
- })
- }
- // 添加新项弹窗
- onOk = () => {
- const { visible, metadata, inputName, inputText, type, indx, dateSel, dataStart, dataEnd } = this.state
- // if (visible == "add") {
- let list = []
- if (!inputName) {
- Taro.showToast({
- title: "请输入字段名称",
- icon: 'none'
- })
- return
- }
- if (type == "text") {
- if (!inputText) {
- Taro.showToast({
- title: "请输入字段值",
- icon: 'none'
- })
- return
- }
- list.push({ name: inputName, value: inputText, type: type })
- } else if (type == "date") {
- if (!dateSel) {
- Taro.showToast({
- title: "请选择日期",
- icon: 'none'
- })
- return
- }
- list.push({ name: inputName, value: dateSel, type: type })
- } else if (type == "dateRange") {
- if (!dataStart) {
- Taro.showToast({
- title: "请选择开始日期",
- icon: 'none'
- })
- return
- }
- if (!dataEnd) {
- Taro.showToast({
- title: "请选择结束日期",
- icon: 'none'
- })
- return
- }
- list.push({ name: inputName, value: dataStart + " " + dataEnd, type: type })
- }
- if (visible == "edit") {
- let nlist = metadata
- nlist[indx] = list[0]
- this.setState({
- metadata: nlist,
- visible: "",
- })
- } else {
- this.setState({
- metadata: [...metadata, ...list],
- visible: "",
- })
- }
- }
- // 修改章节名
- onChapTitle = (i, e) => {
- const data = this.state.chapters
- data.forEach(function (item, index) {
- if (index == i) {
- item.title = e.detail.value
- }
- })
- this.setState({
- chapters: data
- })
- }
- // 修改章节关键词
- onChapKeywords = (i, e) => {
- const data = this.state.chapters
- data.forEach(function (item, index) {
- if (index == i) {
- let val = e.detail.value.replace(/[\uff0c]/g, ",")
- item.keywords = !val ? [] : val.split(",")
- }
- })
- this.setState({
- chapters: data
- })
- }
- // 修改章节内容
- onChaoContent = (i, e) => {
- const data = this.state.chapters
- data.forEach(function (item, index) {
- if (index == i) {
- item.content = e.detail.html
- }
- })
- this.setState({
- chapters: data
- })
- }
- // 二级确认
- toggleVisible = () => {
- this.setState({
- popup: !this.state.popup,
- })
- }
- // 删除章节
- delChap = () => {
- const list = this.state.chapters
- list.splice(this.state.delIndex, 1)
- for (var i = 0; i < list.length; i++) {
- list[i].fullTitle = this.getTitleWithChineseNum(i, list[i].title)
- }
- this.setState({
- chapters: list
- })
- this.toggleVisible()
- }
- // 保存
- onSubmit = () => {
- const { data, metadata, chapters } = this.state
- if (!data.companyId) {
- Taro.showToast({
- title: "请填写关联企业!",
- icon: 'none'
- })
- return
- }
- if (!data.name) {
- Taro.showToast({
- title: "请填写报告类型!",
- icon: 'none'
- })
- return
- }
- if (!data.reportName) {
- Taro.showToast({
- title: "请填写项目名称!",
- icon: 'none'
- })
- return
- }
- if (!data.supervisor) {
- Taro.showToast({
- title: "请填写负责人!",
- icon: 'none'
- })
- return
- }
- if (!data.keywords) {
- Taro.showToast({
- title: "请填写关键词!",
- icon: 'none'
- })
- return
- }
- data.metadata = metadata
- data.chapters = chapters
- let payload = data
- this.props.report(payload).then((data) => {
- Taro.showToast({
- title: "保存成功",
- icon: 'none'
- })
- }).catch(() => {
- })
- }
- // 另存为模板
- onReportTemplate = () => {
- const { data, metadata, chapters, name, tags } = this.state
- if (!this.state.name) {
- Taro.showToast({
- title: "请填写模板名称!",
- icon: 'none'
- })
- return
- }
- let payload = {
- chapters,
- companyId: data.companyId || 0,
- id: 0,
- logoPath: data.logoPath || '',
- metadata,
- name,
- reportName: data.reportName || '',
- tags,
- }
- this.props.onReportTemplate(payload).then((data) => {
- this.onTemCancel()
- Taro.showToast({
- title: "模板保存成功",
- icon: 'none'
- })
- }).catch(() => {
- })
- }
- // 取消
- onTemCancel = () => {
- this.setState({
- name: '',
- tags: [],
- template: false,
- })
- }
- render() {
- // if (!this.state.loaded) {
- // return <Loading />
- // }
- const { data, visible, metadata, type, chapterType, chapters, aeList } = this.state
- return (
- <View className='home main'>
- <View className='home-item'>
- <View className='home-item-tit'>关联企业</View>
- <View className='home-item-vals'>
- <Picker mode='selector' range={aeList} rangeKey="name"
- onChange={this.onAeChange}
- >
- <View className='home-item-vals-txt'>{data.companyName || "请选择关联企业"}</View>
- </Picker>
- <View className='home-item-vals-bt'>
- <Button size='mini' type='primary' onClick={() => { this.setState({ newvb: true }) }}>+新增企业</Button>
- </View>
- </View>
- </View>
- <View className='home-item'>
- <View className='home-item-tit'>报告类型</View>
- <Input
- value={data.name}
- className='home-item-val'
- placeholder='请输入报告类型'
- onChange={e => {
- let obj = data
- obj.name = e.detail.value
- this.setState({
- data: obj,
- })
- }}
- />
- </View>
- <View className='home-item'>
- <View className='home-item-tit'>项目名称</View>
- <Input
- value={data.reportName}
- className='home-item-val'
- placeholder='请输入项目名称'
- onChange={e => {
- let obj = data
- obj.reportName = e.detail.value
- this.setState({
- data: obj,
- })
- }}
- />
- </View>
- <View className='home-item'>
- <View className='home-item-tit'>项目负责人</View>
- <Input
- value={data.supervisor}
- className='home-item-val'
- placeholder='请输入项目负责人'
- onChange={e => {
- let obj = data
- obj.supervisor = e.detail.value
- this.setState({
- data: obj,
- })
- }}
- />
- </View>
- <View className='home-item'>
- <View className='home-item-tit'>企业LOGO</View>
- <ImagePicker
- id={data.id}
- keyId="reportId"
- api='/gw/user/logo'
- urls={data.logoPath}
- onChange={(path) => {
- let obj = data
- obj.logoPath = path
- this.setState({
- data: obj,
- })
- }}
- />
- </View>
- <View className='home-item'>
- <View className='home-item-tit'>关键词</View>
- <Input
- value={data.keywords}
- className='home-item-val'
- placeholder='请输入关键词'
- onChange={e => {
- let obj = data
- obj.keywords = e.detail.value
- this.setState({
- data: obj,
- })
- }}
- />
- </View>
- {
- metadata.map((item, index) =>
- <View className='home-item' key={index}
- onClick={() => {
- this.setState({
- indx: index,
- type: item.type,
- inputName: item.name,
- visible: "edit",
- inputText: item.type == "text" ? item.value : undefined,
- dateSel: item.type == "date" ? item.value : undefined,
- dataStart: item.type == "dateRange" ? item.value.split(" ")[0] : undefined,
- dataEnd: item.type == "dateRange" ? item.value.split(" ")[1] : undefined,
- })
- }}
- >
- <View className='home-item-tits'>
- <View className='home-item-tits-txt'>{item.name}</View>
- <View className='home-item-tits-bt'>
- <Button size='mini' type='warn'
- onClick={e => {
- e.stopPropagation()
- let list = this.state.metadata
- list.splice(index, 1)
- this.setState({
- metadata: list
- })
- }}
- >删除</Button>
- </View>
- </View>
- {item.type == "text" && <View className='home-item-val'>{item.value}</View>}
- {item.type == "date" && <View className='home-item-val'>{item.value}</View>}
- {item.type == "dateRange" && <View className='home-item-val'>{item.value.replace(" ", " → ")}</View>}
- </View>
- )
- }
- <View className='home-item'>
- <Picker mode='selector' range={this.state.selector} rangeKey="name"
- onChange={this.onChange}
- >
- <Button style={{ background: "#0079c2", color: "#fff" }}>+添加新项</Button>
- </Picker>
- </View>
- <View className='home-line' />
- {
- chapters.map((item, index) =>
- <View className='home-item' key={index} style={{ marginBottom: 10, }}>
- <View className='home-item-tits'>
- <Input
- value={item.title}
- className='home-item-tits-txt'
- style={{ borderBottom: "1px solid #d9d9d9" }}
- onChange={(e) => {
- this.onChapTitle(index, e)
- }}
- />
- <View className='home-item-tits-bt'>
- <Button size='mini' type='warn'
- onClick={e => {
- e.stopPropagation()
- this.setState({
- delIndex: index
- })
- this.toggleVisible()
- }}
- >删除</Button>
- </View>
- </View>
- <View className='home-item-text'>
- <View>章节关键词:</View>
- <Input
- value={item.keywords.toString().replace(/,/g, ",")}
- className='home-item-text-val'
- placeholder='输入逗号分割'
- onChange={(e) => {
- this.onChapKeywords(index, e)
- }}
- />
- </View>
- <View className='home-item-editor'>
- <RuiEditor
- keys={index}
- placeholder={item.content || '文字内容...'}
- onInput={e => {
- this.onChaoContent(index, e)
- }}
- />
- </View>
- {/* <View className='home-item-editor' contenteditable="true">{item.content || "请填写内容..."}</View> */}
- <View className='home-item-bottom'>
- <View></View>
- <Button
- style={{ margin: 0 }}
- size='mini'
- type='primary'
- onClick={() => {
- this.getGenerate(item.title, index)
- }}
- >Al生成</Button>
- </View>
- </View>
- )
- }
- <View className='home-item'>
- <Picker mode='selector' range={chapterType} rangeKey="title"
- onChange={this.onChapterChange}
- >
- <Button style={{ background: "#0079c2", color: "#fff" }}>+添加章节</Button>
- </Picker>
- </View>
- <View className='home-item' style={{ marginTop: 30, paddingBottom: 30 }}>
- <Button type='primary' onClick={this.onSubmit}>保存</Button>
- <Button style={{ background: "#0079c2", color: "#fff" }}
- onClick={() => {
- this.setState({
- template: true
- })
- }}
- >另存为模板</Button>
- </View>
- {/* 新增项 */}
- {visible != "" &&
- <View className='mask'>
- <View className='count'>
- <View className='count_top'>
- <Input
- value={this.state.inputName}
- className='count_top_input'
- placeholder='字段名称'
- onChange={e => { this.setState({ inputName: e.detail.value }) }}
- />
- {type == "text" &&
- <Input
- value={this.state.inputText}
- style={{ marginTop: 15 }}
- className='count_top_input'
- placeholder='请输入字段值'
- onChange={e => { this.setState({ inputText: e.detail.value }) }}
- />}
- {type == "date" &&
- <Picker mode='date' value={this.state.dateSel}
- onChange={e => {
- this.setState({
- dateSel: e.detail.value,
- })
- }}>
- <View className={!this.state.dateSel ? 'count_top_dates' : 'count_top_date'}>
- {!this.state.dateSel ? "请选择日期" : this.state.dateSel}
- </View>
- </Picker>
- }
- {type == "dateRange" &&
- <Picker mode='date' value={this.state.dataStart}
- onChange={e => {
- this.setState({
- dataStart: e.detail.value,
- })
- }}>
- <View className={!this.state.dataStart ? 'count_top_dates' : 'count_top_date'}>
- {!this.state.dataStart ? "开始日期" : this.state.dataStart}
- </View>
- </Picker>
- }
- {type == "dateRange" &&
- <Picker mode='date' value={this.state.dataEnd}
- onChange={e => {
- this.setState({
- dataEnd: e.detail.value,
- })
- }}>
- <View className={!this.state.dataEnd ? 'count_top_dates' : 'count_top_date'}>
- {!this.state.dataEnd ? "结束日期" : this.state.dataEnd}
- </View>
- </Picker>
- }
- </View>
- <View className='count_foot'>
- <Button onClick={this.onCancel}>取消</Button>
- <Button style={{ marginTop: 0 }}
- onClick={this.onOk}
- >确认</Button>
- </View>
- </View>
- </View>}
- {/* 新增企业 */}
- {this.state.newvb &&
- <View className='mask'>
- <View className='count'>
- <View className='title'>新增企业名称</View>
- <View className='count_top'>
- <Input
- value={this.state.name}
- className='count_top_input'
- placeholder='请输入新企业名称'
- onChange={e => { this.setState({ name: e.detail.value }) }}
- />
- </View>
- <View className='count_foot'>
- <Button onClick={this.onAeCancel}>取消</Button>
- <Button style={{ marginTop: 0 }}
- onClick={this.onAeOk}
- >确认</Button>
- </View>
- </View>
- </View>}
- {/* 二级确认 */}
- {this.state.popup &&
- <View className='mask'>
- <View className='count'>
- <View className='title' style={{ margin: "60px 0" }}>确认删除吗?</View>
- <View className='count_foot'>
- <Button onClick={this.toggleVisible}>取消</Button>
- <Button style={{ marginTop: 0 }}
- onClick={this.delChap}
- >确认</Button>
- </View>
- </View>
- </View>}
- {/* 另存为模板 */}
- {this.state.template &&
- <View className='mask'>
- <View className='count'>
- <View className='title'>另存为模板</View>
- <View className='count_top' style={{ margin: "20px 0" }}>
- <Input
- value={this.state.name}
- className='count_top_input'
- placeholder='模板名称'
- onChange={e => { this.setState({ name: e.detail.value }) }}
- />
- <Input
- value={this.state.tags.toString().replace(/,/g, ",")}
- style={{ marginTop: 15 }}
- className='count_top_input'
- placeholder='模板标签,输入逗号分割'
- onChange={e => {
- let val = e.detail.value.replace(/[\uff0c]/g, ",")
- this.setState({
- tags: !val ? [] : val.split(",")
- })
- }}
- />
- </View>
- <View className='count_foot'>
- <Button onClick={this.onTemCancel}>取消</Button>
- <Button style={{ marginTop: 0 }}
- onClick={this.onReportTemplate}
- >确认</Button>
- </View>
- </View>
- </View>
- }
- </View >
- )
- }
- }
- export default ReportDetail
|