aiCreateDialog.vue 26 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662
  1. <template>
  2. <el-dialog title="AI生成PPT" :visible.sync="dialogVisibleAiCreate" :append-to-body="true" width="700px"
  3. :before-close="handleClose" class="dialog_diy">
  4. <div style="height: 500px; padding: 15px" v-loading="loading" element-loading-text="小可正在努力生成中,请稍等...">
  5. <!-- <div class="t_box">
  6. <span>选择:</span>
  7. <el-radio-group v-model="radio" @change="changeRadio">
  8. <el-radio :label="0">PPT</el-radio>
  9. <el-radio :label="1">教案</el-radio>
  10. <el-radio :label="2">视频</el-radio>
  11. </el-radio-group>
  12. </div> -->
  13. <div class="t_box" v-if="steps == 1" style="height: 100%">
  14. <textarea style="height: 100%;width:calc(100% - 260px)" rows="10" class="binfo_input binfo_textarea" cols
  15. placeholder="请生成大纲" v-model="outline"></textarea>
  16. <div class="template_box">
  17. <span class="title">选择模板</span>
  18. <div class="template_list">
  19. <div class="template_item" :class="{ active: index == templateIndex }"
  20. v-for="(item, index) in templateList" :key="index" @click="changeTemplate(index)">
  21. <img :src="item.img" alt="" />
  22. </div>
  23. </div>
  24. </div>
  25. </div>
  26. <div style="height: 100%" v-else>
  27. <wOffice v-if="url" :url="url"></wOffice>
  28. </div>
  29. </div>
  30. <span slot="footer" class="dialog-footer">
  31. <el-button @click="aiGet(2)" type="primary" :disabled="loading">重新生成大纲</el-button>
  32. <el-button @click="aiGet(1)" type="primary" :disabled="loading">{{
  33. url ? "重新生成PPT" : "生成PPT"
  34. }}</el-button>
  35. <el-button @click="steps = 1" type="primary" v-if="steps == 2">上一步</el-button>
  36. <el-button @click="steps = 2" type="primary" v-else-if="steps == 1 && url">下一步</el-button>
  37. <el-button @click="confirm" type="primary">确 定</el-button>
  38. <el-button @click="close">关 闭</el-button>
  39. </span>
  40. </el-dialog>
  41. </template>
  42. <script>
  43. import Pptxgen from "pptxgenjs";
  44. import wOffice from "../components/wOffice.vue";
  45. import { v4 as uuidv4 } from "uuid";
  46. import { color } from "highcharts";
  47. export default {
  48. components: {
  49. wOffice,
  50. },
  51. props: {
  52. dialogVisibleAiCreate: {
  53. type: Boolean,
  54. default: false,
  55. },
  56. courseName: {
  57. type: String,
  58. default: "",
  59. },
  60. infoData: {
  61. type: Array,
  62. default: "",
  63. },
  64. courseTypeId: {
  65. type: Array,
  66. default: "",
  67. },
  68. CourseTypeJson: {
  69. type: Object,
  70. default: () => ({}),
  71. }
  72. },
  73. // 根据用户给你的参考资料
  74. data() {
  75. return {
  76. userid: this.$route.query.userid,
  77. radio: 0,
  78. aiJson: {
  79. ppt: `## 任务
  80. 请生成关于${this.courseName},为教师生成这节课的教学ppt,页数在20页左右。PPT的内容主要是讲解该课程中所有可能涉及到的知识点。
  81. ## 工作流
  82. 1. 从用户提供的参考资料中提取10个最重要的知识点(知识点水平限制在小学和初中),并输出。
  83. 2. 针对10个知识点中的每个,你使用1~3页ppt详细的对知识点进行讲解。你的讲解词应该在100token左右
  84. 3. 讲解完所有知识点后,再根据知识点出5道单选题(放在5页ppt中)
  85. ## 限制
  86. - 你不能输出错误的知识,如果你实在不清楚,输出“对不起,我不确定”
  87. - 你不能输出违反伦理的内容`,
  88. word: "",
  89. video: "",
  90. },
  91. aiUrl: {
  92. ppt: "",
  93. word: "",
  94. video: "",
  95. },
  96. detail: "",
  97. loading: false,
  98. url: "",
  99. uJson: {},
  100. outline: "",
  101. steps: 1,
  102. templateList: [
  103. // { img: 'https://ccrb.s3.cn-northwest-1.amazonaws.com.cn/model1-11719468995661.png', img2: 'https://ccrb.s3.cn-northwest-1.amazonaws.com.cn/model1-21719469026755.png',color:'17094F' },
  104. // { img: 'https://ccrb.s3.cn-northwest-1.amazonaws.com.cn/model2-11719469051869.png', img2: 'https://ccrb.s3.cn-northwest-1.amazonaws.com.cn/model2-21719469040181.png',color:'052B37' },
  105. // { img: 'https://ccrb.s3.cn-northwest-1.amazonaws.com.cn/model3-11719469071576.png', img2: 'https://ccrb.s3.cn-northwest-1.amazonaws.com.cn/model3-21719469092087.png',color:'1D5869' },
  106. // { img: 'https://ccrb.s3.cn-northwest-1.amazonaws.com.cn/model4-11719469106190.png', img2: 'https://ccrb.s3.cn-northwest-1.amazonaws.com.cn/model-4-21719469125318.png',color:'372213' },
  107. // { img: 'https://ccrb.s3.cn-northwest-1.amazonaws.com.cn/model5-11719295908696.png', img2: 'https://ccrb.s3.cn-northwest-1.amazonaws.com.cn/model5-21719295930345.png',color:'674D40' },
  108. { img: require('../../../assets/icon/ppt/model1-1.png'), img2: require('../../../assets/icon/ppt/model1-2.png'),color:'17094F' },
  109. { img: require('../../../assets/icon/ppt/model2-1.png'), img2: require('../../../assets/icon/ppt/model2-2.png'),color:'052B37' },
  110. { img: require('../../../assets/icon/ppt/model3-1.png'), img2: require('../../../assets/icon/ppt/model3-2.png'),color:'1D5869' },
  111. { img: require('../../../assets/icon/ppt/model4-1.png'), img2: require('../../../assets/icon/ppt/model4-2.png'),color:'372213' },
  112. { img: require('../../../assets/icon/ppt/model5-1.png'), img2: require('../../../assets/icon/ppt/model5-2.png'),color:'674D40' },
  113. ],
  114. templateIndex: 0,
  115. };
  116. },
  117. watch: {
  118. dialogVisibleAiCreate(newValue, oldValue) {
  119. if (newValue) {
  120. this.aiGet(2);
  121. }
  122. },
  123. },
  124. methods: {
  125. handleClose(done) {
  126. this.close();
  127. done();
  128. },
  129. close() {
  130. this.$emit("update:dialogVisibleAiCreate", false);
  131. },
  132. confirm() {
  133. if (this.url) {
  134. this.$emit("createAiPpt", this.uJson);
  135. } else {
  136. this.$message.error("请先生成ppt");
  137. }
  138. },
  139. changeRadio() {
  140. if (this.radio == 0) {
  141. this.detail = this.aiJson.ppt;
  142. }
  143. if (this.radio == 1) {
  144. this.detail = this.aiJson.word;
  145. }
  146. if (this.radio == 2) {
  147. this.detail = this.aiJson.video;
  148. }
  149. },
  150. createFileid(url) {
  151. let _this = this;
  152. return new Promise((resolve, reject) => {
  153. try {
  154. _this.ajax
  155. .put("https://gpt4.cocorobo.cn/upload_file_knowledge", {
  156. url: url,
  157. })
  158. .then((res) => {
  159. let _data = res.data.FunctionResponse;
  160. if (_data.result && _data.result.id) {
  161. resolve(_data.result.id);
  162. }
  163. })
  164. .catch(function (error) {
  165. resolve("");
  166. });
  167. } catch (e) {
  168. resolve();
  169. }
  170. });
  171. },
  172. async aiGet(type) {
  173. if (this.loading) {
  174. this.$message.error("正在生成中,请稍后");
  175. return;
  176. }
  177. this.url = "";
  178. this.uJson = {};
  179. let _this = this;
  180. let fileid = [];
  181. if (_this.infoData.length) {
  182. for (var i = 0; i < _this.infoData.length; i++) {
  183. if (_this.infoData[i].fileid) {
  184. fileid.push(_this.infoData[i].fileid);
  185. } else {
  186. let _fileid = await _this.createFileid(_this.infoData[i].url);
  187. if (_fileid) {
  188. _this.infoData[i].fileid = _fileid;
  189. _this.$forceUpdate();
  190. fileid.push(_fileid);
  191. }
  192. }
  193. }
  194. }
  195. console.log("fileid=========", fileid);
  196. let mclass = [];
  197. if (_this.courseTypeId.length) {
  198. for (var i = 0; i < _this.courseTypeId.length; i++) {
  199. let _sid = _this.courseTypeId[i];
  200. for (
  201. var j = 0;
  202. j <
  203. _this.CourseTypeJson["34628934-d02f-11ec-8c78-005056b86db5"].length;
  204. j++
  205. ) {
  206. if (
  207. _sid ==
  208. _this.CourseTypeJson["34628934-d02f-11ec-8c78-005056b86db5"][j].id
  209. ) {
  210. mclass.push(
  211. _this.CourseTypeJson["34628934-d02f-11ec-8c78-005056b86db5"][j]
  212. .name
  213. );
  214. }
  215. }
  216. }
  217. }
  218. let message = "";
  219. if (type == 1) {
  220. message = `NOTICE
  221. Role: 你是ppt内容设计大师,能力是从用户提供的文件资料中提取最重要的学科概念作为ppt参考内容,最后根据Context要求的流程要求输出ppt内容。
  222. Output: Provide your output in json format.
  223. Language: Please use the same language as the user requirement, if the user speaks Chinese, the specific text of your answer should also be in Chinese.
  224. ATTENTION: Use '##' to SPLIT SECTIONS, not '#'. Output format carefully referenced "Format example".
  225. Instruction: Based on the context, follow "Format example", write content.
  226. # Context
  227. ## 任务
  228. 将参考#大纲内容,为教师生成这节课的教学ppt。PPT的内容主要是讲解该课程中所有可能涉及到的知识点,根据大纲内容生成ppt内容。
  229. ## 每一页输出格式
  230. - 页数:序列数字
  231. - 标题:学科概念(请从给你的大纲中摘取)
  232. - 子标题:知识点(请从给你的大纲中摘取)
  233. - 知识点讲解:针对大纲中的每个知识点,生成200字左右的详细讲解。你的语气应该让小学或初中的学生清晰易懂的讲解。你的讲解词在200 token左右。请尽可能的详细,这对我很重要。
  234. ## 限制
  235. - 你不能输出错误的知识,如果你实在不清楚,修改大纲中的知识点。
  236. - 你不能输出违反伦理的内容
  237. ## 工作流
  238. 1. 针对大纲中的每个知识点,生成200字左右的详细讲解。你的语气应该让小学或初中的学生清晰易懂的讲解。请尽可能的详细,这对我很重要。
  239. 2. 针对大纲中的每个测试,详细设计不同测试题目,例如单选,多选,对错题等。
  240. 3.从用户提供的参考资料中提取5个最重要的学科概念,并输出。
  241. 4.分解每个学科概念为几个子知识点
  242. 5.简要描述每个知识点
  243. 6.生成5个测试题以考察学生的掌握情况
  244. 7.一个知识点一页,一个测试题一页
  245. ## 大纲内容
  246. ${_this.outline}
  247. # Format example
  248. [{"page": "页码(数字)","title": "学科概念(请从给你的大纲中摘取)(标题)","task": "知识点(请从给你的大纲中摘取)(子标题)","points": "知识点讲解:针对大纲中的每个知识点,生成200字左右的详细讲解。你的语气应该让小学或初中的学生清晰易懂的讲解。你的讲解词在100 token左右。请尽可能的详细,这对我很重要。"}]`;
  249. } else {
  250. message = `# 任务
  251. 请根据参考资料,生成关于${this.courseName},为教师生成这节课的教学ppt的大纲,大纲的主要内容课程知识点的讲解与相关练习和测试。你的输出应该符合#输出格式
  252. # 工作流
  253. 1.从用户提供的参考资料中提取5个最重要的学科概念${mclass.length ? "(水平限制在{面向年级}中)" : ""},并输出。
  254. 2.分解每个学科概念为几个子知识点
  255. 3.简要描述每个知识点
  256. 4.生成5个测试题以考察学生的掌握情况
  257. ${mclass.length ? "#参考资料\n面向年级:" + mclass.join(",") : ""}
  258. # 输出格式
  259. - 标题:学科概念1
  260. 1.知识点:知识点1
  261. 2.知识点:知识点2
  262. 3.知识点:知识点3
  263. 4.知识点:知识点4
  264. 5.知识点:知识点5
  265. # 限制
  266. 1.如果有参考资料请根据参考资料,如果没有无需根据参考资料进行,随意发挥。
  267. 2.你不能输出错误的知识。
  268. 3.你不能输出违反伦理的内容。
  269. `;
  270. }
  271. // let params = JSON.stringify({
  272. // // "model": "Chat",
  273. // model: 'gpt-3.5-turbo',
  274. // temperature: 0,
  275. // max_tokens: 4096,
  276. // top_p: 1,
  277. // frequency_penalty: 0,
  278. // presence_penalty: 0,
  279. // messages: [{
  280. // content: message,
  281. // role: 'user'
  282. // }],
  283. // stream: false,
  284. // uid: this.userid,
  285. // mind_map_question: "",
  286. // })
  287. // _this.loading = true
  288. // _this.ajax.post('https://gpt4.cocorobo.cn/chat', params).then(function (response) {
  289. // console.log(response);
  290. // let data = response.data.FunctionResponse
  291. // if (data.choices && data.choices.length && data.choices[0].message) {
  292. // console.log(data.choices[0].message.content);
  293. // try {
  294. // let _data = JSON.parse(data.choices[0].message.content)
  295. // _this.createPpt(_data)
  296. // } catch (e) {
  297. // console.log('error_________________'+e);
  298. // _this.$message.error(data.choices[0].message.content)
  299. // _this.loading = false
  300. // }
  301. // }
  302. // }).catch(function (error) {
  303. // _this.loading = false
  304. // console.log(error);
  305. // });
  306. let parm = {
  307. assistant_id:
  308. type == 1
  309. ? "6063369f-289a-11ef-8bf4-12e77c4cb76b"
  310. : "f8e1ebb2-2e0d-11ef-8bf4-12e77c4cb76b",
  311. message: [{ type: "text", text: message }],
  312. session_name: uuidv4(),
  313. userId: this.userid,
  314. file_ids: fileid.length ? [...fileid] : "",
  315. };
  316. _this.loading = true;
  317. this.ajax
  318. .post("https://gpt4.cocorobo.cn/ai_agent_park_chat", parm)
  319. .then((response) => {
  320. console.log(response);
  321. let data = response.data.FunctionResponse;
  322. if (data.message) {
  323. console.log(data.message);
  324. if (type == 1) {
  325. try {
  326. let _data = JSON.parse(
  327. data.message.replaceAll("```json", "").replaceAll("```", "")
  328. );
  329. _this.createPpt(_data);
  330. _this.steps = 2;
  331. } catch (e) {
  332. console.log("error_________________" + e);
  333. // _this.$message.error(data.message)
  334. try {
  335. // let _data = JSON.parse(data.message.match(/(?<=```json).*?(?=```)/)[0])
  336. var message = data.message;
  337. var jsonStart = message.indexOf("```json") + 7; // `+ 7` 是为了跳过 ```json
  338. var jsonEnd = message.indexOf("```", jsonStart);
  339. if (jsonStart !== -1 && jsonEnd !== -1) {
  340. var jsonString = message
  341. .substring(jsonStart, jsonEnd)
  342. .trim();
  343. var _data2 = JSON.parse(jsonString);
  344. _this.createPpt(_data2);
  345. _this.steps = 2;
  346. } else {
  347. _this.$message.error("生成失败,正在重新生成");
  348. _this.aiGet(type);
  349. }
  350. } catch (error) {
  351. _this.$message.error("生成失败,正在重新生成");
  352. _this.aiGet(type);
  353. _this.loading = false;
  354. }
  355. }
  356. } else {
  357. _this.outline = data.message;
  358. _this.steps = 1;
  359. _this.loading = false;
  360. }
  361. }
  362. })
  363. .catch((error) => {
  364. _this.loading = false;
  365. console.log(error);
  366. });
  367. },
  368. createPpt(array) {
  369. // 1. 创建PPT
  370. const pres = new Pptxgen();
  371. const _slideTou = pres.addSlide();
  372. _slideTou.background = { path: this.templateList[this.templateIndex].img }
  373. _slideTou.addText(this.courseName, {
  374. x: "10%", // 横坐标
  375. y: 3,
  376. width: "90%",
  377. color: this.templateList[this.templateIndex].color,
  378. fontSize: 38, // 字号
  379. align: "center",
  380. });
  381. for (var i = 0; i < array.length; i++) {
  382. // 2. 创建一个PPT页面,每调用一次 pres.addSlide() 都可以生成一张新的页面
  383. // 建议把每个页面的构造抽成一个个函数,然后通过函数调用生成新页面,代码不会很乱
  384. const _slide = pres.addSlide();
  385. _slide.background = { path: this.templateList[this.templateIndex].img2 }
  386. // 3. 调用addTetx(),在PPT页面中插入文字“Hello World from PptxGenJS...”
  387. // 括号里面是对文字的配置,文字横坐标x为1.5,纵坐标y为1.5,字体颜色 363636……
  388. // 关于坐标长度与px的转换 x 1 = 127~128px 左右
  389. const page = i + 1 > 10 ? i + 1 : "0" + (i + 1);
  390. const tempResult1 = page + " " + array[i].title;
  391. _slide.addText(tempResult1, {
  392. x: "10%", // 横坐标
  393. y: 1.1,
  394. width: "90%",
  395. color: this.templateList[this.templateIndex].color,
  396. fontSize: 28, // 字号
  397. align: "center",
  398. });
  399. const tempResult2 = array[i].task;
  400. _slide.addText(tempResult2, {
  401. x: "10%", // 横坐标
  402. y: 1.8,
  403. width: "90%",
  404. color: "222222",
  405. fontSize: 20, // 字号
  406. align: "center",
  407. });
  408. let tempResult3 = '';
  409. if (typeof array[i].points == 'object') {
  410. tempResult3 = array[i].points.join('\n')
  411. } else {
  412. tempResult3 = array[i].points
  413. }
  414. _slide.addText(tempResult3, {
  415. x: "20%", // 横坐标
  416. y: 3.2,
  417. w: "60%",
  418. color: "444444",
  419. fontSize: 18, // 字号
  420. align: "center",
  421. });
  422. }
  423. const _slideWei = pres.addSlide();
  424. _slideWei.background = { path: this.templateList[this.templateIndex].img }
  425. _slideWei.addText("谢谢观看,下课!", {
  426. x: "10%", // 横坐标
  427. y: 3,
  428. width: "90%",
  429. color: this.templateList[this.templateIndex].color,
  430. fontSize: 38, // 字号
  431. align: "center",
  432. });
  433. // 获取PPTX文件的ArrayBuffer
  434. // 保存为 Blob 并处理
  435. pres.write("blob").then((blob) => {
  436. // 现在你有了一个 Blob 对象
  437. console.log(blob);
  438. const file = new File([blob], this.courseName + ".pptx", {
  439. type: "application/vnd.openxmlformats-officedocument.presentationml.presentation",
  440. });
  441. console.log(pres);
  442. this.beforeUpload(file);
  443. });
  444. },
  445. beforeUpload(event) {
  446. var file = event;
  447. var credentials = {
  448. accessKeyId: "AKIATLPEDU37QV5CHLMH",
  449. secretAccessKey: "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",
  450. }; //秘钥形式的登录上传
  451. window.AWS.config.update(credentials);
  452. window.AWS.config.region = "cn-northwest-1"; //设置区域
  453. var bucket = new window.AWS.S3({ params: { Bucket: "ccrb" } }); //选择桶
  454. var _this = this;
  455. if (file) {
  456. var params = {
  457. Key:
  458. file.name.split(".")[0] +
  459. new Date().getTime() +
  460. "." +
  461. file.name.split(".")[file.name.split(".").length - 1],
  462. ContentType: file.type,
  463. Body: file,
  464. "Access-Control-Allow-Credentials": "*",
  465. ACL: "public-read",
  466. }; //key可以设置为桶的相抵路径,Body为文件, ACL最好要设置
  467. var options = {
  468. partSize: 2048 * 1024 * 1024,
  469. queueSize: 2,
  470. leavePartsOnError: true,
  471. };
  472. bucket
  473. .upload(params, options)
  474. .on("httpUploadProgress", function (evt) {
  475. //这里可以写进度条
  476. // console.log("Uploaded : " + parseInt((evt.loaded * 80) / evt.total) + '%');
  477. })
  478. .send(function (err, data) {
  479. _this.loading = false;
  480. if (err) {
  481. _this.$message.error("上传失败");
  482. } else {
  483. _this.url = data.Location;
  484. _this.uJson = {
  485. name: file.name,
  486. url: data.Location,
  487. type: 3,
  488. };
  489. console.log(data.Location);
  490. }
  491. });
  492. }
  493. },
  494. changeTemplate(index) {
  495. this.templateIndex = index;
  496. }
  497. },
  498. };
  499. </script>
  500. <style scoped>
  501. .dialog_diy>>>.el-dialog {
  502. height: auto;
  503. margin: 15vh auto 0 !important;
  504. }
  505. .dialog_diy>>>.el-dialog__header {
  506. background: #454545 !important;
  507. padding: 15px 20px;
  508. }
  509. .dialog_diy>>>.el-dialog__body {
  510. height: calc(100% - 124px);
  511. box-sizing: border-box;
  512. padding: 0px;
  513. }
  514. .dialog_diy>>>.el-dialog__title {
  515. color: #fff;
  516. }
  517. .dialog_diy>>>.el-dialog__headerbtn {
  518. top: 19px;
  519. }
  520. .dialog_diy>>>.el-dialog__headerbtn .el-dialog__close {
  521. color: #fff;
  522. }
  523. .dialog_diy>>>.el-dialog__headerbtn .el-dialog__close:hover {
  524. color: #fff;
  525. }
  526. .dialog_diy>>>.el-dialog__body,
  527. .dialog_diy>>>.el-dialog__footer {
  528. background: #fafafa;
  529. }
  530. .binfo_input {
  531. width: 100%;
  532. margin: 0;
  533. padding: 5px 7px;
  534. display: block;
  535. min-width: 0;
  536. outline: none;
  537. box-sizing: border-box;
  538. background: none;
  539. border: none;
  540. border-radius: 4px;
  541. background: #fff;
  542. font-size: 15px;
  543. resize: none;
  544. font-family: "Microsoft YaHei";
  545. min-height: 48px;
  546. /* border: 1px solid #3682fc00; */
  547. border: 1.5px solid #cad1dc;
  548. }
  549. .binfo_textarea {
  550. border: 1.5px solid #cad1dc;
  551. font-size: 15px;
  552. resize: none;
  553. /* background: #f6f6f6; */
  554. font-family: "Microsoft YaHei";
  555. }
  556. .binfo_textarea:focus-visible {
  557. border: 1.5px solid #3681fc !important;
  558. }
  559. .binfo_textarea::-webkit-scrollbar {
  560. /*滚动条整体样式*/
  561. width: 6px;
  562. /*高宽分别对应横竖滚动条的尺寸*/
  563. height: 6px;
  564. }
  565. /*定义滚动条轨道 内阴影+圆角*/
  566. .binfo_textarea::-webkit-scrollbar {
  567. border-radius: 10px;
  568. background-color: #eee;
  569. }
  570. /*定义滑块 内阴影+圆角*/
  571. .binfo_textarea::-webkit-scrollbar-thumb {
  572. border-radius: 10px;
  573. -webkit-box-shadow: inset 0 0 6px rgba(0, 0, 0, 0.3);
  574. background-color: rgba(0, 0, 0, 0.1);
  575. }
  576. .t_box {
  577. display: flex;
  578. margin-bottom: 15px;
  579. display: flex;
  580. justify-content: space-between;
  581. }
  582. .t_box>span:nth-child(1) {
  583. min-width: 80px;
  584. font-size: 16px;
  585. color: #000;
  586. }
  587. .template_box{
  588. width: 250px;
  589. }
  590. .template_box > .title{
  591. font-size: 18px;
  592. margin-bottom: 10px;
  593. display: block;
  594. }
  595. .template_list{
  596. overflow: auto;
  597. width: 100%;
  598. height: calc(100% - 31px);
  599. }
  600. .template_item{
  601. cursor: pointer;
  602. width: 100%;
  603. height: 165px;
  604. overflow: hidden;
  605. border-radius: 5px;
  606. box-sizing: border-box;
  607. border: 5px solid #e5e5e5ee;
  608. }
  609. .template_item + .template_item{
  610. margin-top: 10px;
  611. }
  612. .template_item.active{
  613. border: 5px solid #0061ff;
  614. }
  615. .template_item > img{
  616. width: 100%;
  617. height: 100%;
  618. object-fit: cover;
  619. }
  620. </style>