开发笔记1

2020.10.11- 10.15

1.前后端数据交互

1.前端先画列表页面,联调方法;接收返回的数据,渲染数据到表格中,表格中的属性要和返回的字段一致

2.后端写列表接口

2.引用项目组件步骤:

1.import itemComponents from '@/components/Item/itemInfoNew';
2.在你页面的适当位置加上: <itemComponents :action="action" :itemid = "itemId"></itemComponents>
3.在下面js上加上:
props: {
action: {
type: String
},
itemData: {
default: () => {}
}
},
components: {itemComponents},
4.在return的方法上加上 itemId:‘’,
5.在created函数中加上:
if (this.action ===“update”) {
this.formBasic = this.itemData;
}

3.文本框无法输入

v-model="form.字段名"

4.添加页面输入框自动刷新

clearable

5.项目添加页面跳转

  • 在前端列表页面添加新增跳转页面
<div v-if="open">
      <el-dialog :title="title"  :visible.sync="open"    width="90%" append-to-body >
      <!-- MmContractReviewEdit替换为要跳转的页面名 -->
        <MmContractReviewEdit :key="time"   @closeView="closeView" :data="datarow" ></MmContractReviewEdit>
      </el-dialog>
</div>
  • <script>里面定义跳转页面参数
export default {
  components: {
  <!-- MmContractReviewEdit替换为要跳转的页面名,import里引入跳转页面的相对路径 -->
      MmContractReviewEdit: () => import('@/views/market/contractmanagement/MmContractReviewEdit')
    },
}    
// 关闭弹窗及后续操作
closeView() {
    this.open = false
},

6.bug修改-不能插入某id为null

  • 在数据表对应id字段下给个默认sys-guid
    在这里插入图片描述
  • <script>标签下的form表单参数下给某id赋值
<script>    
    from : {
       projectId: "12",
     }
</script>
  • 在对应的方法里面给具体id赋值
submitForm() {
      this.form.projectId="11";
}

7.后端封装数据

    //合同洽谈列表实体
    private List<MmContractNegotiation> mmContractNegotiationList;

    //项目信息实体
    private MmItem mmItem;

    //合同信息实体
    private MmContractReview mmContractReview;
  • 对应业务具体实现
List<MmContractSigning> list = mmContractSigningMapper.selectMmContractSigningList(mmContractSigning);
        for (MmContractSigning contractSigning : list) {
            //查询合同洽谈列表中需要的参数并放入实体
            MmContractNegotiation mmContractNegotiation = new MmContractNegotiation();
            mmContractNegotiation.setSignedId(contractSigning.getSignedId()); //构建查询条件
            List<MmContractNegotiation> list1 = mmContractNegotiationMapper.selectMmContractNegotiationList(mmContractNegotiation);
            contractSigning.setMmContractNegotiationList(list1);
            //根据项目id查询项目信息
            String projectId = contractSigning.getProjectId();
            MmItem mmItem = iMmItemService.selectMmItemById(projectId);
            contractSigning.setMmItem(mmItem);
            //查询合同信息
            MmContractReview mmContractReview = mmContractReviewService.selectMmContractReviewById(projectId);
            contractSigning.setMmContractReview(mmContractReview);


        }
        return list;

2020.10.16- 10.20

1.做组件引入项目信息

  • 再需要做的组件字段添加按钮
<el-col :span="8">
	<el-form-item label="项目编码:" prop="itemCode">
	  <el-input clearable v-model="form.itemCode"  placeholder="根据项目名称自动带出来"  :disabled="true" >
	    <el-button
	      v-if="listVisible"
	      slot="append"
	      icon="el-icon-search"
	      @click="openItemDialog"
	      >选择</el-button
	    >
	  </el-input>
	</el-form-item>
  </el-col>
  • 在方法里定义openItemDialog
methods :{
    openItemDialog() {
         this.open = true;
    },
  }
  • 再from标签里添加(open,title,closeDialog,setItemId参数绑定处理如下)
<el-dialog :visible.sync="open" :title="title" width="90%" :destroy-on-close="true"  append-to-body >
    <itemlist @closeDialog="closeDialog" @setItemId="setItemId"></itemlist>
</el-dialog>
return {
     open: false,
      title: "选择项目列表",
}
methods :{
openItemDialog() {
      this.open = true;
 },
    
    setItemId(data) {
      this.form.itemCode = data.itemCode;
      this.form.itemName = data.itemName;
      this.form.companyName = data.companyName;
 },
    
    closeDialog() {
      this.open = false;
 },
}
  • 赋值
return {
      form: {
        itemCode: "",
        itemName: "",
        companyName:"",
    }
}
  • 根据项目编码引入组件
<script>
import itemComponents from "@/components/Item/itemInfoNew";
</script>

2.时间类型转换异常

在这里插入图片描述

return {
      // Table表绑定参数datainfoList
   datainfoList:[{
        createTime: '',      
        }
      ],
 }

form: {
   createTime: formatDate(new Date()),
 },     
 
method:{
     this.from={
        createTime: formatDate(new Date()),
     }
}

2020.10.21

1. 再表格指定字段设置样子字体为红色加粗

<el-table-column
        label="项目状态"
        align="center"
        prop="projectStatus"
      >
      <template slot-scope="scope">
		    <div class="text_color">{{scope.row.projectStatus}}</div>
	  </template>
</el-table-column>

<style scoped="scoped">
	.text_color{color:red; font-weight: bold;}
</style>

2.table表格里面默认本来没有数据,需要点击新增按钮新增一行,(若没点新增之前出来一行数据)则需要删除绑定该table表格数据源里面的默认值对象或者列表或对象

3. 将默认0 1状态改成具体的汉化状态

<el-table-column
        label="项目状态"
        align="center"
        prop="mmItem.formStatus"  >
   <template slot-scope="scope">
       <span v-if='scope.row.mmItem.formStatus == "0"'>竣工</span>
       <span v-if='scope.row.mmItem.formStatus == "1"'>在建</span>
   </template>
</el-table-column>

4. 前端合并对象同时获取data 和 mmItem对象里面的数据

created() {
    if (!(this.action === "add")) {
       this.form = Object.assign(this.data, this.data.mmItem);
      //console.log(this.data)
      this.listVisible = true;
    }
  },

5.根据某字段搜索查询某条数据

  • 再实体类中添加对应的字段,生成对应的setter和getter方法
  • 再试xml里面作为条件写出对应的查询语句

6.删除

  • 再对应的删除列表添加主键id字段
 <!-- v-if="false" 隐藏主键id在前端列表页面中展示 -->
 
<el-table-column
        v-if="false"
        align="center"
        prop="settlementId"        
/>
  • 找到对应删除按钮所绑定的函数
<!--  @click="handleDelete(scope.row)" -->

<el-button
            size="mini"
            type="text"
            icon="el-icon-delete"
            @click="handleDelete(scope.row)"
            v-hasPermi="['SmSettlementUpload:SmSettlementUpload:remove']"
            >删除
</el-button>
  • 删除方法
/** 删除按钮操作 */
method : {
handleDelete(row) {
    const settlementIds = row.settlementId || this.ids;
     this.$confirm('是否确认删除SmSettlementUpload编号为"' + settlementIds + '"的数据项?', "警告", {
          confirmButtonText: "确定",
          cancelButtonText: "取消",
          type: "warning"
        }).then(function() {
          return delSmSettlementUpload(settlementIds);
        }).then(() => {
          this.getList();
          this.msgSuccess("删除成功");
        }).catch(function() {});
    },
 }

2020.10.22

1.前端传值

1、父组件向子组件传值
①:在父组件的中定义
<add-appraisalview   :actionType="actionType" @closeView="closeView"></add-appraisalview>

在这里插入代码片

② 再return中定义需要传递的参数名
eg:   actionType{}
③ 赋值
④:在子组件中接受参数
props: {
    actionType:“”
  }
2、子组件向父组件传值,子组件调用父组件的方法
<add-appraisalview  ref="addview @close="closeView"></add-appraisalview>
1、在父组件上定义close的方法,row为传子组件的值:
 closeView(row) {
        this.addviewdialog = false;
        this.getList();
      },
2、在子组件上使用:closeView要和父页面的名称一致
this.$emit("closeView",row);
3、父组件调用子组件的方法
<add-appraisalview  ref="addview @close="closeView"></add-appraisalview>
在父组件上使用:
 this.$refs.item.setItemInfoData(this.form.itemId);
在子组件上必须有setItemInfoData的方法

1.1子组件向父组件传值

1.父页面引用弹框(声明传值函数、关闭函数)

<el-dialog :visible.sync="businessTalkOpen" width="90%" title="商务洽谈"  :show-close="false" append-to-body>
          <businessTalk :businessTalkInfo="businessTalkInfo" @businessTalkData="businessTalkData" @businessTalkClose="businessTalkClose"></businessTalk>
</el-dialog>

1.2父页面接收方法值在这里插入图片描述
1.3子页面直接传值(在确认、关闭等需要传值的函数中传递需要的值)

this.$emit("businessTalkData", this.form);

2.间距

<el-col :span="24" style="text-align: right"></el-col>

3.表格序号前多选框(例如批量删除数据)

<el-table-column type="selection" width="55" align="center" />

4.格式化

//页面对应字段下
:formatter="xxxFormat"

//方法(传值)
    xxxFormat(row, column) {
      return this.selectDictLabel(this.xxxOptions, row.mmItem.xxx);
  },

2020.10.23-10.29

1.Oracle中where…and不能并存问题

  1. 方法1:再where后加1=1
  2. 方法2:再对应的sql上面添加<trim prefix="(" suffix=")" suffixOverrides=",">

2.多表联查sql模板

select
1.字段,   --要查询的字段
2.字段   --用逗号拼接最后一个不要逗号
from 
表名1    --主表(查询结果应与主表数据对应)
left join 表名2 on 2.xxxId=1.xxxId --关联表,   xxxId为外键

3.项目选择器复合数据查询(根据项目名称带出多表信息)

  • 后端再重写一个关联查询sql,和对应的接口
SELECT
        TE.FILENAME,
        op.BIDDINGUNITSNAME,
        sr.SUB_CONTRACT_CODE,
        mi.COMPANY_ID,
        mi.COMPANY_NAME,
        mi.ITEM_CODE,
        mi.ITEM_NAME
        FROM
        MM_ITEM mi
        LEFT JOIN PM_TENDER_EVALUATION te ON te.PROJECT_ID = mi.item_id
        LEFT JOIN PM_OPENING_RESULTS op ON op.TENDER_EVALUATION_ID = te.TENDER_EVALUATION_ID
        LEFT JOIN PM_SUBCONTRACT_REVIEW sr ON sr.TENDER_EVALUATION_ID = te.TENDER_EVALUATION_ID
where mi.item_id  = #{projectId}
  • 前端再js里单独写一个调用该后端的查询接口
// 根据projectId查询有关项目信息
export function getPmSubcontractVisaInfo(projectId) {
  return request({
    url: '/project/PmSubcontractVisa/info/' + projectId,
    method: 'get'
  })
}
  • 前端代码(多表信息需要的数据)
// 注意:getPmSubcontractVisaInfo该接口再import里引入
 
import {
  getPmSubcontractVisaInfo,
}
//在选择器方法中调用接口,取到对应的值,并赋值给表单中对应的输入框
 methods: {
    setItemId(data) {
        this.form.projectId = data.itemId;
        this.form.mmItem.companyName = data.companyName;
        this.form.mmItem.itemCode = data.itemCode;
        this.form.mmItem.itemName = data.itemName;
      getPmSubcontractVisaInfo(data.itemId).then((response) => {
        //v-model="form.pmTenderEvaluation.filename"
        this.form.pmTenderEvaluation.filename = response.data.pmTenderEvaluation.filename;
        this.form.pmOpeningResults.biddingunitsname = response.data.pmOpeningResults.biddingunitsname;
        this.form.pmSubcontractReview.subContractCode = response.data.pmSubcontractReview.subContractCode;
      });
    },
}
  • 具体做组件引入项目信息(参考:2020.10.16 做组件引入)

4.修改页面数据没有回显

  • 在父组件(列表页面)传值,子组件(修改页面)接收,根据层级关系取值: .xxx(对应多表对象实体名)
  1. 列表页面父组件绑定子组件
components: {
      SubcontractVisaEdit: () => import('@/views/project/subpackage/SubcontractVisa/SubcontractVisaEdit')
    },

  修改页面子组件并接收
 
 /** 修改按钮操作 */
    handleUpdate(row) {
      this.action='update'
      const subcontractId = row.subcontractId || this.ids
      getPmSubcontractVisa(subcontractId).then(response => {
        this.data = response.data; //将查询到的值给到修改页面data
        this.open = true; //打开弹窗
        this.title = "修改分包签证基本信息"; //弹窗标题设置
      });
    },
  1. 修改页面子组件并接收
    注意:修改页面中不能定义data为空:data[]
props: {
    action: {
      type: String,
    },
    data: {
      default: () => {},
    },
    
  },
  • 修改页面子组件需要回显的数据用对应的实体.xxx取值

2020.10.30-11.18

1.oracle自动计算时间round函数用法

  • 单表
SELECT
months_between(sysdate,ENTRY_TIME),  -- 两者时间函数(sysdate当前时间,后者是需要做差的时间字段)
trunc(months_between(sysdate,ENTRY_TIME)/12) siling -- 返回指定格式函数(siling 需要的(计算)扩充字段,表里不需要创建)
from cm_employee_work_record
  • 多表
在字段追加条件后面加
ROUND ( MONTHS_BETWEEN (SYSDATE, wr.ENTRY_TIME) / 12, 0 ) siling   --sysdate当前时间,后者是某张表里需要做差的字段,0,默认取整,1-结果保留一位

3.自动生成四位流水码和对应的年月日 ,例如:FCZG+YYYYMM+4位流水码

  • 再SYS_SERIALNUMRULE表里添加对应的编码配置
  • 前端找到dataConfig.js配置文件,配置对应的编码
  • 父页面跳子页面的弹框中传值 :fromCode=“fromCode”
 <!-- 添加的弹框 -->
    <div v-if="open">
       <el-dialog :visible.sync="open" :title="title"  width="98%" :destroy-on-close="true">
         <edit  :key="time" :action="action" :data="Data" :fromCode="fromCode" @closeView="closeView"></edit>
       </el-dialog>
    </div>
  • 引入组件

import { getSequnce } from “@/api/system/sequnce”;

  • return中定义 fromCode:“”,
  • 再前端对应页面需要处理自动生成流水码位置加
<!--  PmAssetsHouse对应的编码名 -->
getSequnce(this.mySystemDataConfig.sysMenuCode.PmAssetsHouse).then((response)=>{
            this.fromCode = response.data.fromCode;
   })
  • 子页面接受父页面传过来的值
  fromCode: {
      type: String,
    },
  • created中赋值

this.form.xxxCode = this.fromCode;

4.根据弹窗选择弹出不同的页面(如图:)

在这里插入图片描述

  • 前端弹窗页面
<el-dialog :visible.sync="visible" title="请选择新增的房产来源类型" width="30%">
      <el-radio v-model="value" label="1">房产自购</el-radio>
      <el-radio v-model="value" label="2">房产自建</el-radio>
      <el-radio v-model="value" label="3">抵房款</el-radio>
      <span slot="footer" class="dialog-footer">
        <el-button size="mini" @click="visible = false">取 消</el-button>
        <el-button type="primary" size="mini" @click="handleOk">确 定</el-button>
      </span>
</el-dialog>
  • 再方法里写对应的选择类型(value 是选择弹窗类型v-model绑定类型,open是绑定添加弹窗的参数,handleOk绑定弹窗参数)
handleOk() {
        this.time = new Date().getTime()    
        if (this.value === '1') {
          this.title = '新增房产自购'
          this.value ='1'
          this.open =true
        //自动生成流水码和时间
          getSequnce(this.mySystemDataConfig.sysMenuCode.PmAssetsHouse).then((response)=>{
            this.fromCode = response.data.fromCode;
            this.realSource = true
            this.visible = false
          })

        } else if(this.value === '2'){
          this.title = '新增房产自建'
          this.value = '2'
           this.open =true
          getSequnce(this.mySystemDataConfig.sysMenuCode.selfBuilt).then((response)=>{
            this.fromCode = response.data.fromCode;
            this.realSource = true
            this.visible = false
          })
        }else{
          this.title = '新增抵房款'
          this.value = '3'
          this.open =true
          getSequnce(this.mySystemDataConfig.sysMenuCode.houseMoney).then((response)=>{
            this.fromCode = response.data.fromCode;
            this.realSource = true
            this.visible = false
          })
        }
        this.action = "add";
  },
  • 对应的修改类型操作(data是绑定的对应修改列表的参数,realSource对应的弹窗页面类型字段,action是绑定添加弹窗的参数)
handleUpdate(row) {
      this.time = new Date().getTime();
      const houseId = row.houseId || this.ids;
      getPmAssetsHouse(houseId).then((response) => {
      if (response.data.realSource == '1') {
          this.title = '修改房产自购信息'         
          this.type = '1'
        } else if(response.data.realSource == '2'){
          this.title = '修改房产自建信息'
          this.type = '2'
        }else {
          this.title = '修改抵房款信息'
          this.type = '3'
        }
        this.Data = response.data;
        this.action = 'update'
        this.open = true
        this.form.realSource = this.value;
      });
    },
  • 对应弹窗页面的字段类别区分,再对应文本框中添加v-if=“type == ‘x’”
<el-form-item label="备注:" prop="remarks" v-if="type == '3'||type == '1'">

注意:前端定义某参数再return里面

2020.11.19-12.04

1.导出组件引用

  • 在【系统管理-系统导出配置】中配置模块和导出数据。(字段类型为数据字典的,一定要先在字典管理中增加对应的字典类型)
  • 在导出的页面中引用公共组件:@/components/export/index (exportConfig: () => import(“@/components/export/index”) )
  • 弹窗的配置,再对应的导出页面添加导出弹窗
<弹窗名 :key="time" @closeExportView="closeExportView" :configData="exportConfigData" :businessType="'item'"></弹窗名>
    其中exportConfigData是保存已选择的配置信息;businessType为对应在【系统管理-系统导出配置】中设置的导出配置编码名称
例如:
<div v-if="exportVisible">
   <el-dialog v-dialogDrag :visible.sync="exportVisible" :title="exportTitle" width="90%" :destroy-on-close="true" >
      <exportConfig :key="time" @closeExportView="closeExportView" :configData="exportConfigData" :businessType="'projectPlanning'"></exportConfig>
   </el-dialog>
</div>
  • 弹窗参数对应的初始化,再return下定义参数
 return {
      exportVisible: false,
      exportTitle: "导出配置",
      time: "",
      exportConfigData: [],
}
  • closeExportView 回调函数书写
closeExportView(data)
  {
    this.exportConfigData = data;
	//处理自己的业务
}handleExport() { },   页面绑定的导出按钮
例如:/** 导出按钮操作 */
    closeExportView(data) {
      this.exportConfigData = data;
      this.exportVisible = false;
      const queryParams = this.queryParams;
      this.$confirm('是否确认导出所有项目策划信息数据项?', "警告", {
          confirmButtonText: "确定",
          cancelButtonText: "取消",
          type: "warning"
        }).then(function() {
          return exportEmployee(queryParams);
        }).then(response => {
          this.download(response.msg);
        }).catch(function() {});
    },
     /** 导出按钮操作 */
    handleExport() {
      this.exportVisible = true;
    },

2.附件上传按钮以及附件信息页面

  • 再对应页面上加上传按钮
 <el-upload ref="ownerConfirmFile" :file-list="uploadFileList" :action="uploadFileAction" :before-upload="FileUpload">
          <el-button size="small" type="primary" icon="el-icon-upload">附件上传</el-button>
</el-upload>
  • 按钮下面写出具体上传附件信息
 <el-table :data="dataSource">
     <el-table-column align="center" label="文件名称">
         <template slot-scope="scope">
             <el-input placeholder="请输入" v-model="scope.row.fileName"/>
         </template>
     </el-table-column>
<el-table>
  • 再return下定义参数
 return{
      //附件上传配置
      uploadFileList: [],
      uploadFileAction: "https://jsonplaceholder.typicode.com/posts/",
}
  • 定义上传方法
 method:{
 /**附件上传方法**/
    FileUpload(file) {
      let isRightSize = file.size / 1024 / 1024 < 2;
      if (!isRightSize) {
        this.$message.error("文件大小超过 2MB");
      }
      return isRightSize;
    },
}
  • 效果图
    在这里插入图片描述

2020.12.04-12.07

1.分割线标签

<el-divider></el-divider>

2.表单新样式

<div slot="header" class="clearfix">
    <span>合同信息:</span>
</div>
    <el-form :inline="true" :model="form" size="mini" ref="form" label-width="130px">
      <el-row>
         <el-col :span="5" :offset="2" border="true">序号</el-col>
         <el-col :span="9">条款名称</el-col>
         <el-col :span="8">条款内容</el-col>
      </el-row>
          <el-divider></el-divider>
      <el-row>
         <el-col :span="3" :offset="2">1</el-col>
         <el-col :span="8">合同金额(元):</el-col>
         <el-col :span="8">
            <el-input placeholder="" clearable v-model="form.contractAmount" style="width: 100%" :disabled="true"></el-input>
         </el-col>
       </el-row>
       <el-row>
            <el-col :span="3" :offset="2">2</el-col>
            <el-col :span="8">承包范围:</el-col>
            <el-col :span="8">
              <el-input v-model="form.contractScope" placeholder="" clearable style="width: 100%" :disabled="true"/>
            </el-col>
          </el-row>
          <el-row>
            <el-col :span="5" :offset="8">开工日期:</el-col>
            <el-col :span="8">
              <el-date-picker type="date" placeholder="" v-model="form.commencementDate" clearable style="width: 100%"
                              :disabled="true"></el-date-picker>
            </el-col>
          </el-row>
       <el-row>
            <el-col :span="3" :offset="2">3</el-col>
            <el-col :span="3">工期:</el-col>
            <el-col :span="5">竣工日期:</el-col>
            <el-col :span="8">
              <el-date-picker type="date" placeholder="" v-model="form.completionDate" clearable style="width: 100%" :disabled="true"></el-date-picker>
            </el-col>
        </el-row>
          <el-row>
            <el-col :span="5" :offset="8">总工期:</el-col>
            <el-col :span="8">
              <el-date-picker type="date" placeholder="" v-model="form.totalDuration" clearable style="width: 100%" :disabled="true"></el-date-picker>
            </el-col>
          </el-row>

效果图
在这里插入图片描述

2020.12.07-12.15

1.vue项目,el-table给某一列添加样式(默认红色加粗)

//table标签
<el-table :cell-style="changeCellStyle"> </el-table>
method :{
 changeCellStyle(row, column, rowIndex, columnIndex) {
      if (row.column.label === "项目文档状态") {
        return "color: red";
        ("font-weight: bold"); // 修改的样式
      } else {
        return "";
      }
    },
}

2.校验时间(开始时间不能大于结束时间)

  1. 再选择结束日期对应的页面添加
  :picker-options="xxxx"
<el-col :span="8">
       <el-form-item label="结束日期" prop="nend">
	        <el-date-picker clearable size="small" style="width: 200px" v-model="form.nend" type="date" :picker-options="xxx" value-format="yyyy-MM-dd" placeholder="选择结束日期" @change="dateNchange"></el-date-picker>
       </el-form-item>
</el-col>

2.return下写时间校验

 return {
 xxxx :{ 
      disabledDate: time => {
      if (this.form.开始时间) {
      return time.getTime() < new Date(this.form.开始时间).getTime()- 86400000;
      }
    }
  },
}

3.自动计算时间差(结束时间减开始时间)

1.工具类写一个计算时间差方法

export function calcTotalDay(startDateStr, endDateStr) {
      let date1 = new Date(startDateStr);             // 开始时间
      let date2 = new Date(endDateStr);               // 结束时间
      let timeSub = date2.getTime() - date1.getTime();  // 时间差毫秒
      return (timeSub / 86400000)+1;
}

2.页面的开始日期,结束日期绑定参数

 @change="xxx"

3.引入方法

  import { calcTotalDay } from "@/utils/dateUtil";

4.调calcTotalDay方法

methods: {
     xxx() {
         if (this.form.开始时间 != null && this.form.结束时间 != null) {
         this.form.oworkHours = calcTotalDay(this.form.开始, this.form.结束);
      }
    },
}

4.element-ui设置表单某字段为必填项

return{
 // 表单校验
rules:{
  xxx字段名 : [
      { required: true, message: "xxxx不能为空", trigger: "blur" },
     ],
   },
 }

5.element-ui表单动态校验(例如校验某选择为否后,某表单为必填项----(是否基本单位=‘否’ 换算比例为必填))

1.return里写校验某表单为必填项

 //ratio换算比例
  return{
   //表单校验
      rules:{
   //是否基本单位=‘否’ 换算比例为必填
         ratio: [
          {
            validator : 方法名 ,
            message : "换算比例不能为空",
            trigger : "change",
          },
        ],
  }}
  1. data里面写表单校验方法
data ( ) {
    //是否基本单位=‘否’ 换算比例为必填(ratio需要校验的字段名(换算比例),baseUnit校验前的条件(0-否,1-是)-是否基本单位)
    const 方法名 = (rule, value, callback) => { 
      if(this.form.ratio== ' ' && this.form.baseUnit=='0'){
        return callback(new Error('换算比例不能为空'));
      }
       return callback();
    }
}
  1. 再form里定义下ratio ,baseUnit
 form :{
      ratio :"",
      baseUnit :"",
}

6.点击提交按钮,修改列表中表单状态,同时将原项目名变为新项目名(默认1草稿2生效)

  1. 后端写提交接口

mapper

 //修改表单状态
  int commitIds(String  eicIds);
//跟据某id修改原项目id
 int updateProject(@Param("empId")String empId, @Param("belongsProjectId") String belongsProjectId);

service

int commitIds(String eicIds);   

impl

//提交修改表单状态和项目id
@Override
    public int commitIds(String  eicIds) {
        for (int i = 0; i < eicIds.length; i++) {
            //查询变更的新项目id
            String eicId = eicIds[i];
            PmEmpItemChange p = pmEmpItemChangeMapper.selectPmEmpItemChangeById(eicId);//查到项目id
            //修改员工项目信息中的项目id
            pmEmpItemChangeMapper.updateProject(p.getEmpId(), p.getNitemId());
            //提交生效
            PmEmpItemChange pmEmpItemChange = new PmEmpItemChange();
            pmEmpItemChange.getEmpId();
        }
        return pmEmpItemChangeMapper.commitIds(eicIds);
    }

controller

//修改表单状态
@PreAuthorize("@ss.hasPermi('labor:PmEmpItemChange:commit')")
    @Log(title = "PmEmpItemChange", businessType = BusinessType.UPDATE)
    @PutMapping("/{eicIds}")
    public AjaxResult commitIds(@PathVariable String[] eicIds)
    {
        return toAjax(pmEmpItemChangeService.commitIds(eicIds));
    }

xml

#修改表单状态
<update id="commitIds" parameterType="String">
        update  pm_emp_item_change set form_status = 2 where eic_id in
        <foreach item="eicId" collection="array" open="(" separator="," close=")">
            #{eicId}
        </foreach>
    </update>
#修改项目id
<update id="updateProject" parameterType="String">
        update  PM_EMPLOYEE_INFO set BELONGS_PROJECT_ID = #{belongsProjectId} where id  = #{empId}
</update>
  1. 前端

页面提交按钮加绑定参数

:businessType="'xxxx'"

return下定义

xxxx: {},

提交方法

//提交
commitIds(row) {
      const eicIds = row.eicId || this.ids;
      if (this.empItemChange.formStatus == "2") {         //校验提交生效后,不能重复提交  
        this.msgSuccess("该记录已经生效,无须重复提交");
      } else {
        this.$confirm(
          '是否确认提交"' + eicIds + '"的项目数据?',
          "警告",
          {
            confirmButtonText: "确定",
            cancelButtonText: "取消",
            type: "warning",
          }
        )
          .then(function () {
            return commitIds(eicIds);
          })
          .then(() => {
            this.getList();
            this.msgSuccess("提交成功");
          })
          .catch(function () {});
      }
    },

多选框中操作,不能提交多条

handleSelectionChange(selection) {
      this.xxxx = selection[0];
    },

删除校验,生效不能删除,草稿可删除

handleDelete(row) {
      const eicIds = row.eicId || this.ids;
      if (row.formStatus == "2") {            //校验生效不能删除
        this.msgSuccess("该记录已经生效,不可删除");
      } else {
        this.$confirm(
          '是否确认删除"' + eicIds + '"的数据项?',
          "警告",
          {
            confirmButtonText: "确定",
            cancelButtonText: "取消",
            type: "warning",
          }
        )
          .then(function () {
            return delPmEmpItemChange(eicIds);
          })
          .then(() => {
            this.getList();
            this.msgSuccess("删除成功");
          })
          .catch(function () {});
      }
    },

7.数字类型校验

  1. 校验表单必须为数字类型
    v-model.number
    :rules=“[{ type: ‘number’, message: ‘xxx必须为数字值’}]”
 <el-col :span="24">
       <el-form-item label="精度" prop="unitDecimal" label-width="20%" :rules="[{ type: 'number', message: '精度必须为数字值'}]">
           <el-input v-model.number="form.unitDecimal" placeholder="请输入精度" />
        </el-form-item>
 </el-col>

2020.12.15-12.23

1.点编辑直接带出来数据

  1. 后端写一个查询接口,封装根据某某id带出数据
  2. 前端再列表页面调查询接口,再编辑页面给需要带出来的数据赋值
    handleAdd绑定编辑按钮参数,getInfoById查询接口
 handleAdd() {
      this.time = new Date().getTime();
      const openingResultsDetailid = this.openingResultsDetailid || this.ids;
      getInfoById(openingResultsDetailid).then((response) => {
          this.Data = response.data;        
	            this.fromCode = response.data.fromCode;
	            console.log(response.data);
	            this.open = true;
	            this.action = "add";
	            this.title = "添加保证金返还";
        );
    },

编辑页面赋值

created() {
    if (this.action === "update") {
      this.form = this.data;
    }else{
        this.form.xxxId= this.data.xxxId;
        this.form.xxx字段1= this.data.xxx字段1;
        this.form.xxx字段2= this.data.xxx字段2;
    }
  },

2.上传组件引用

  1. html页面写上传组件
<el-row :gutter="24">
    <el-col :span="16" >
       <upload :uploadData="uploadData"></upload>
     </el-col>
</el-row>
  1. 引入上传组件
components:{
  upload: () => import("@/components/upload")
 },
  1. 定义uploadData,并生成uuid
//busiId -主单id ,type-附件类型
 return {
      form: {
        returnDepositId:this.get_uuid(),   //前端生成主单uuid
      },
       uploadData:{
              busiId:'',
              createName:this.$store.state.user.name,
              type:'parentText'
  },
}

4.获取主单id

 created() {
    this.uploadData.busiId = this.form.returnDepositId;  
    if (this.action === "update") {
      this.form = this.data;
      this.uploadData.busiId = this.data.returnDepositId;
  }
}

2020.12.23-12.28

1.按钮禁用

若页面分为列表(list)页面和编辑页面(edit),编辑有多个按钮,根据操作对不同按钮做相应的禁用,(例如:新增时做提交按钮禁用,修改时做保存按钮禁用)

  1. 父组件列表页面找到对应编辑页面的组件弹框,绑定参数:disabled=“disabled1” :disabled=“disabled2”
 <!-- 添加的弹框 -->
    <div v-if="open">
      <el-dialog
        :visible.sync="open"
        :title="title"
        width="90%"
        :destroy-on-close="true"
      >
        <edit
          :key="time"
          :action="action"
          :data="Data"
          :fromCode="fromCode"
          :disabled1="disabled1"
          :disabled2="disabled2"
          @closeView="closeView"
        ></edit>
      </el-dialog>
    </div>
  1. 列表页面定义禁用参数 disabled1:true,
  2. 列表页面找到对应操作需要禁用的按钮,调禁用参数this.disabled1 = false; this.disabled2 = true;
 例如: /** 新增按钮操作 */
    handleAdd() {
      this.time = new Date().getTime();
      const openingResultsDetailid = this.openingResultsDetailid || this.ids;
      getInfoById(openingResultsDetailid).then((response) => {
        this.Data = response.data;
        getSequnce(this.mySystemDataConfig.sysMenuCode.returnDepositCode).then(
          (response) => {
             this.fromCode = response.data.fromCode;
             console.log(response.data);
             this.open = true;
             this.disabled1 = false;
             this.disabled2 = true;
             this.action = "add";
             this.title = "添加保证金返还";
          }
        );
      });
    },

 /** 修改按钮操作 */
    handleUpdate(row) {
      this.time = new Date().getTime();
      console.log(row.returnDepositId);
      const returnDepositId = row.returnDepositId || this.ids;
      console.log(returnDepositId);
      getPmReturnDeposit(returnDepositId).then((response) => {
        this.Data = response.data;
        this.action = "update";
        this.open = true;
        this.disabled2 = false;
        this.disabled1 = true;
        this.title = "修改保证金返还";
      });
    },
  1. 编辑页,在需要禁用的按钮上分别绑禁用参数 :disabled=“disabled1”,
    再子组件接收父组件传值
 props:{  
      disabled1:true,
      disabled2:true,
     }

2.引入上传附件组件,若再前端生成uuid,新增接口显示操作失败,很有可能是编辑页面判断新增或修改不是以id作为判断,也有可能是与父组件列表里面的子组件编辑页面的弹框绑定的区分是新增还是修改的参数action有关

submitForm() {
      this.$refs["form"].validate((valid) => {
        if (valid) {
          if (this.action == "update") {
            updatePmReturnDeposit(this.form).then((response) => {
              if (response.code === 200) {
                this.msgSuccess("修改成功");
                this.$emit("closeView");
              }
            });
          } else {
            addPmReturnDeposit(this.form).then((response) => {
              if (response.code === 200) {
                this.msgSuccess("新增成功");
                this.$emit("closeView");
              }
            });
          }
         }
      });
    },
  

3.修改单条sql

<update id="接口名" parameterType="java.lang.String">
        update  表名 set 某状态= 1 where 主单id= #{主单id}
</update>
例如:
<update id="commitId" parameterType="java.lang.String">
        update  pm_return_deposit set status = 1 where return_deposit_id = #{returnDepositId}
</update>

4.修改多条sql,foreach循环

<update id="接口名" parameterType="String">
        update  表名 set 某状态 = 2 where 主单id in
        <foreach item="主单id" collection="array" open="(" separator="," close=")">
            #{主单id}
        </foreach>
</update>
例如:
<update id="commitIds" parameterType="String">
        update  pm_emp_item_change set form_status = 2 where eic_id in
        <foreach item="eicId" collection="array" open="(" separator="," close=")">
            #{eicId}
        </foreach>
</update>

2020.12.23-12.28

1.随机点上面列表一行,带出来下面子表的列表数据

  1. 加到上面列表处
@row-click="rowClick" highlight-current-row="true"
  1. 定义方法
 rowClick(row, column, event) {
     const 主单id = row.主单id
     获取明细信息接口getxxx(主单id).then(response => {
        this.需要带出来子表数据绑定的参数 = response.data.需要带出来子表数据绑定的参数
  })
}

3.return里面定义需要带出来子表数据绑定的参数
4.下面需要带出来的列表数据绑定子表所绑定的参数

2020.12.28-01.15

1.校验金额,保留两位

return{
     //表单校验
    rules:{
          金额字段名: [
          {
            required: true,
            pattern: /^(([1-9]{1}\d*)|(0{1}))(\.\d{1,2})?$/,
            message: "请输入合法的金额数字,最多两位小数",
            trigger: "blur",
          },
        ],

   },
}

2.字典里追加状态(字典里没有该状态,但是列表带出数据默认需要展示该状态)

1.在列表页面的字典翻译那块追加状态

methods:{
        //xxx状态字典翻译
    xxxFormat(row, column) {
           if(row.字段名 == null || row.字段名 == ''){
               return '追加状态';
          }
               return this.selectDictLabel(this.字段状态绑定值, row.字段名)
      },
例如:
     // 收取状态字典翻译
    receivedStatusFormat(row, column) {
          if(row.receivedStatus == null || row.receivedStatus == ''){
             return '未编辑';
        }
             return this.selectDictLabel(this.receivedStatusOptions, row.receivedStatus)
      },
  }

3.vue自动计算金额,且保留两位

  1. 相乘
      //计算维保金额=结算金额*维保金比例
<el-col :span="8">
   <el-form-item label="结算金额(元):" prop="settleAmount">
      <el-input
         size="small"
         class="shorter-shower-inputter"
         v-model="form.settleAmount"
         placeholder="请输入结算金额"
         @input="paymentChanges()"       //计算金额绑定方法名
      />
   </el-form-item>
</el-col>
method:{
    paymentChanges() {
        var _this = this;
        var data1 = _this.form.settleAmount; //结算金额
        var data2 = _this.form.fundRate; //维保金比例
        // 乘法
        let r1, r2, m;
       _this.form.maintenanceAmount =  parseFloat((data1 * data2 )).toFixed(2);   //保留两位正则表达式
  },
}
  1. 做差
   //计算实际维保金额=维保金额-扣除金额
<el-col :span="8">
     <el-form-item label="扣除金额(元):" prop="deductionAmount">
       <el-input
         size="small"
         class="shorter-shower-inputter"
         v-model="form.deductionAmount"
         placeholder="请输入扣除金额"
         @input="paymentChange()"       //计算金额绑定方法名
       />
     </el-form-item>
</el-col>
method:{
	paymentChange() {
	      var _this = this;
	      var data1 = _this.form.maintenanceAmount; //维保金额
	      var data2 = _this.form.deductionAmount; //扣除金额
	      // 乘法
	      let r1, r2, m;
	      _this.form.actualAmount = parseFloat(data1  - data2).toFixed(2);   //保留两位
    },
}

4.默认带出来列表数据,编辑页需要新增自己主单信息,校验新增有数据之后不能在做新增只能修改

  1. 找到列表页新增按钮绑定的方法
method:{
  handleAdd() {
	  this.time = new Date().getTime();
	  const planId = this.planId || this.ids;       //带出上一级数据主单id
	  const wfId = this.wfId || this.ids;             //做校验自己主表id
  if (wfId != '') {
      this.msgSuccess("该记录已保存,不可编辑");
    } else {   
      getInfoById(planId).then((response) => {    //带出编辑页Edit页面数据接口
         console.log(response.data)
         this.Data = response.data;
         this.open = true
         this.action = 'add'
         this.title = '维保金回收(新增页)'
});
   }
},
}
  1. 定义主单id wfId:[], 定义上一级主单id planId: [],
  2. 多选框id处理
 // 多选框选中数据
    handleSelectionChange(selection) {
         this.wfId = selection.map(item => item.wfId)      //主单id做校验处理
         this.ids = selection.map(item => item.wfId)       //同上
         this.planId = selection.map(item => item.planId)   //上一级id处理
         this.single = selection.length !== 1
         this.multiple = !selection.length
    },

5.日期格式化

  1. 需要的格式化日期后面加:formatter=“dateFormat”
<el-table-column label="维保终止日期" align="center" prop="terminationDate" :formatter="dateFormat"/>
  1. 方法里加
 methods: {
    dateFormat: function(row, column, cellValue, index) {
      var t = new Date(cellValue)// row 表示一行数据, createTime 表示要格式化的字段名称
      if(!t){
        return ''
      }
	      let year = t.getFullYear()
	      let month = this.dateIfAddZero(t.getMonth()+1)
	      let day = this.dateIfAddZero(t.getDate())
	      let hours = this.dateIfAddZero(t.getHours())
	      let minutes = this.dateIfAddZero(t.getMinutes())
	      let seconds = this.dateIfAddZero(t.getSeconds())
	      return year + '-' + month + '-' + day+ ' ' + hours + ':' + minutes+ ':' + seconds
    },
    dateIfAddZero : function (time) {
         return time < 10 ? '0'+ time : time
    }
}

2020.01.15-01.21

1.点编辑带出来项目信息,该项目信息是引入公用组件,带有选择器做处理要求不能选择

1.再引入项目组件里改该组件action后面绑定的状态名,去掉组件里@setItemInfo=“setItemInfo”

<itemComponents :action="itemAction" :itemid="itemId"></itemComponents> 
  1. 定义itemAction,给个view状态
 itemAction:'view',
  1. 再props里面接收组件传值
 props:{
    itemId: {
         type: String
      },
    components: {
         itemComponents
     },
}

2.点编辑按钮,进入修改页面(默认有保存,提交,导出,打印按钮操作)

  1. 若编辑页子单有数据则直接修改保存,若子单没有数据,则需要新增一条子单数据保存
  2. 若流程状态为已审批状态,需要加页面校验,不能编辑
  3. 若流程状态为草稿状态,可以编辑,具体实现如下
  /** 编辑修改按钮操作 */
      handleUpdate() {  
          this.itemId = this.rowInfo.projectId; 
          const tenderBondPayPutInId = this.rowInfo.tenderBondPayPutInId;
        if(this.rowInfo.flowStatus ==="0"||this.rowInfo.flowStatus===null)
        {
          this.time = new Date().getTime();
          if (tenderBondPayPutInId===null||tenderBondPayPutInId==='undefined')
          {
            this.datarow = {};
            this.action = "add";
            this.open = true;
            this.title = "新增保证金支付申请";
          }
          else{
            getTenderBondPayPutIn(tenderBondPayPutInId).then(response => {
            this.datarow = response.data;
            this.action = "update";
            this.open = true;
            this.title = "修改保证金支付申请";});
          }
        }
        else
        {
          this.msgSuccess("该项目已审批,无需编辑");
        }
      },

//参数说明:1)datarow --组件修改弹框页面绑定的data值 , 
(2)定义rowInfo:{},  多选框中处理 this.rowInfo = selection[0];

3.查看按钮操作

  1. 选定列表绑定的一条查看按钮绑定字段,若子单没有数据则需要做页面校验,先编辑存一条子单数据再查看
  2. 点查看项目信息,需要隐藏掉编辑页面的保存和提交按钮,不做展示具体实现如下
    (1)再需要做查看按钮字段绑定查看按钮@click=“handleView(scope.row)”
<el-table-column label="项目名称" align="center" prop="itemName">
     <template slot-scope="scope">
       <div style="color:blue;text-decoration:underline;cursor:pointer;" @click="handleView(scope.row)">{{ scope.row.itemName }}</div>
     </template>
</el-table-column>

//核心代码:<div style="color:blue;text-decoration:underline;cursor:pointer;" @click="handleView(scope.row)">{{ scope.row.itemName }}</div>

(2)查看点击事件方法及校验

 //查看按钮操作
      handleView(row) {  
        this.itemId = row.projectId; //项目id赋值做项目回显
        const tenderBondPayPutInId = row.tenderBondPayPutInId;
        console.log(tenderBondPayPutInId);
        if (tenderBondPayPutInId===null||tenderBondPayPutInId==='undefined')
        {
          this.msgSuccess("该项目未做保证金支付申请,请先【编辑】");
        }
        else{
          getTenderBondPayPutIn(tenderBondPayPutInId).then(response => {
          this.time = new Date().getTime();
          this.datarow = response.data;
          this.open = true;
          this.action = "view";
          this.title = "查看保证金支付申请";
          });
        }
      },

(3)编辑页面不需要的按钮处理核心代码 v-if=“!(action === ‘view’)”

<el-button type="primary" v-if="!(action === 'view')" icon="el-icon-check" size="mini" @click="submitForm">保存</el-button>                   
<el-button type="primary" v-if="!(action === 'view')" icon="el-icon-thumb" size="mini" @click="commitId" 
    v-hasPermi="['TenderBondPayPutIn:TenderBondPayPutIn:submit']">提交</el-button>

(4)编辑页修改回显赋值,做判断,核心代码this.action === “view”

 if (this.action === "update"||this.action === "view") {
        this.formBasic = this.data;
   }

4.input输入框输入数字校验

//正则校验input输入框里只能输入数字
οninput="value=value.replace(/[^\d.]/g,'')"
例如:
<el-col :span="8">
      <el-form-item label="转入金额:" prop="shiftToMoney">
         <el-input v-model="formBasic.shiftToMoney" placeholder="请输入转入金额"
                  oninput="value=value.replace(/[^\d.]/g,'')"
                  clearable style=" width: '100%'"/>
      </el-form-item>
</el-col>
//正则校验input输入框里只能输入大于0的数字
οninput="value=value.replace(/\D|^0/g,'')"

5.修改两种状态的sql

<update id="接口名" parameterType="java.lang.String">
      update  表名 set 状态1= 默认值, 状态2= 默认值 where  xx_id= #{xxId}
</update>

6.后端判断id !=nul 是新增还是修改

MmTenderBondPayPutIn checkPoJo = mmTenderBondPayPutInMapper.selectMmTenderBondPayPutInById(mmTenderBondPayPutIn.getTenderBondPayPutInId());
if (checkPoJo != null){
      mmTenderBondPayPutIn.setUpdateBy(currentUser.getUser().getUserId().toString());
      return  mmTenderBondPayPutInMapper.updateMmTenderBondPayPutIn(mmTenderBondPayPutIn);
  }else {
      mmTenderBondPayPutIn.setCreateBy(currentUser.getUser().getUserId().toString());
      return mmTenderBondPayPutInMapper.insertMmTenderBondPayPutIn(mmTenderBondPayPutIn);
}

2020.01.21-01.27

1.引入公共上传组件,区分不同上传文件类型

<upload :uploadData="uploadDatas(form.主单id,'上传类型别名自定义')"></upload>  //核心代码

      <el-col :span="24">
            <el-form-item label="电子文档">
              <upload :uploadData="uploadDatas(form.id,'electronicDocument')"></upload>     
            </el-form-item>
          </el-col>
          <el-col :span="24">
            <el-form-item label="签订版合同附件">
              <upload :uploadData="uploadDatas(form.id,'hetongfujian')"></upload>
            </el-form-item>
          </el-col>
          <el-col :span="24">
            <el-form-item label="结束合同评审">
              <upload :uploadData="uploadDatas(form.id,'endReview')"></upload>
            </el-form-item>
          </el-col>
//引入组件
components: {
      upload: () => import("@/components/upload"),
      },
//上传公用方法
methods:{
  //categoryType自定义命名
uploadDatas(id, categoryType) {
        var uploadData = {
          busiId: id,
          createName: this.$store.state.user.nickName,
          categoryType: categoryType,
          isUpload: this.action=='add'||this.action=='update' //是否允许上传文件
        }
        return uploadData
      },
}

图示
在这里插入图片描述

2020.01.27-02.09

1.列表展示上级推送过来的数据,某状态给默认值

在查询列表的sql需要给追加条件默认值的字段加如下语句
nvl(表别名.字段名,状态) as 字段名,
例如:
nvl(cs.contract_states,0) as contract_states,

cs.update_by,
cs.del_flag,
nvl(cs.contract_states,0) as contract_states,
SU.NICK_NAME AS create_by,

2.点击提交,同时给两张不同表里插入一条数据

1.封装需要插入数据的实体
2.业务实现层,用自己实体接收

 例如:
public int commit(MmContractSigning mmContractSigning) {
        MmCollaborativeitem mmCollaborativeitem = mmContractSigning.getMmCollaborativeitem();
        //合作年度时间处理
        //mmCollaborativeitem.setCooperationyear(mmCollaborativeitem.getCooperationyear().substring(0,5)); //拿到值截取年份存入
        mmCollaborativeitem.setCooperationyear(DateUtils.getDate().substring(0,4)); //获取当前时间的年份存入
         //部门表里插入数据
        SysDept sysDept = mmContractSigning.getSysDept();
       //通过掉部门查询,查出parentId==公司id
        Long parentId = sysDept.getParentId();
        SysDept dept = sysDeptMapper.selectDeptById(parentId);
        //Ancestors的值构成:项目表的Ancestors,companyId=parentId
        sysDept.setAncestors(dept.getAncestors()+","+parentId);
        sysDept.setDeptType("Z03");
        sysDept.setCreateTime(DateUtils.getNowDate());
        sysDeptMapper.insertDept(sysDept);
        return mmCollaborativeitemMapper.insertMmCollaborativeitem(mmCollaborativeitem);
    }

3.截取日期四位年份

mmCollaborativeitem.setCooperationyear(DateUtils.getDate().substring(0,4)); //获取当前时间的年份存入
WebRTC是一个实时通信的开源项目,其源码开发涵盖了视频编码、打包以及流程模块等。在这个开发笔记中,我将对WebRTC的视频编码打包流程模块进行图解说明。 WebRTC的视频编码打包流程主要涉及到以下几个模块:视频源模块、视频编码模块、打包模块和传输模块。 首先是视频源模块,它负责从摄像头或者文件中获取视频数据。该模块通过调用底层API来获取视频帧,并将其传递给下一个模块。 接下来是视频编码模块,它负责将获取到的视频帧进行压缩编码。具体来说,该模块会对视频帧进行压缩算法处理,将其转换为可传输的数据格式。WebRTC支持多种视频编码算法,如VP8、H.264等。 然后是打包模块,它负责将编码后的视频数据打包成数据包。该模块会对视频数据进行分片,并为每个片设置头部信息,以便接收端能够正确解析和处理。 最后是传输模块,它负责将打包好的视频数据通过网络传输到接收端。该模块依赖于网络协议,如UDP或TCP等进行数据传输。在传输过程中,还会涉及到网络拥塞控制和丢包重传等机制,以保证传输的稳定性和可靠性。 以上就是WebRTC视频编码打包流程模块的图解说明。通过这些模块的协作,WebRTC能够实现实时的视频传输和通信功能。开发者可以根据需要对各个模块进行定制和扩展,以满足不同的应用场景需求。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值