controller.dart 22 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634
  1. import 'dart:convert';
  2. import 'dart:io';
  3. import 'package:flutter/material.dart';
  4. import 'package:flutter/services.dart';
  5. import 'package:flutter_inappwebview/flutter_inappwebview.dart';
  6. import 'package:get/get.dart';
  7. import 'package:image_picker/image_picker.dart';
  8. // import 'package:open_file/open_file.dart';
  9. import '../../../../common/api/index.dart';
  10. import '../../../../common/models/index.dart';
  11. import '../../../../common/routers/index.dart';
  12. import '../../../../common/utils/index.dart';
  13. import '../../../../common/values/index.dart';
  14. import '../../../../common/widgets/index.dart';
  15. import '../../../common/create_form/index.dart';
  16. import '../../../common/preview_image/index.dart';
  17. import '../../../common/process_webview/index.dart';
  18. import '../../../common/video_player/index.dart';
  19. import '../cms_app/index.dart';
  20. import 'index.dart';
  21. class CmsDocumentController extends GetxController implements JsNavigationInterface {
  22. CmsDocumentController();
  23. final state = CmsDocumentState();
  24. final channel = O2FlutterMethodChannelUtils();
  25. // webview控件的控制器
  26. final GlobalKey webViewKey = GlobalKey();
  27. InAppWebViewController? webviewController;
  28. // webview 通用方法
  29. final webviewHelper = WebviewHelper();
  30. // 安装转化js
  31. var isInstallJsName = false;
  32. // 拍照 图片选择
  33. final ImagePicker _imagePicker = ImagePicker();
  34. final _eventBus = EventBus();
  35. String? docId;
  36. // cms 创建文档使用的对象
  37. CmsAppData? _app;
  38. CmsCategoryData? _category;
  39. Map<String, dynamic>? _cmsMessageData;
  40. /// 在 widget 内存中分配后立即调用。
  41. @override
  42. void onInit() {
  43. super.onInit();
  44. }
  45. /// 在 onInit() 之后调用 1 帧。这是进入的理想场所
  46. @override
  47. void onReady() {
  48. var map = Get.arguments;
  49. if (map != null) {
  50. state.title = map["title"] ?? "cms_document_title".tr;
  51. OLogger.d("文档标题 title: ${state.title} ");
  52. String id = map["documentId"] ?? "";
  53. OLogger.d("文档id: $id ");
  54. if (id.isNotEmpty) {
  55. docId = id;
  56. _initCmsUrl(id, map["options"]);
  57. }
  58. }
  59. super.onReady();
  60. }
  61. @override
  62. void closeWindow() {
  63. OLogger.d('执行了 jsapi closeWindow ');
  64. _eventBus.emit(EventBus.cmsDocumentCloseMsg, 'close');
  65. Get.back();
  66. }
  67. @override
  68. void goBack() {
  69. OLogger.d('执行了 jsapi goBack ');
  70. tapBackBtn();
  71. }
  72. @override
  73. void setNavigationTitle(String title) {
  74. OLogger.d('执行了 jsapi setNavigationTitle $title ');
  75. state.title = title;
  76. }
  77. void _initCmsUrl(String id, Map<String, dynamic>? options) async {
  78. var url = O2ApiManager.instance.getCmsDocumentUrl(id) ?? '';
  79. if (options != null) {
  80. var readonly = options['readonly'];
  81. if (readonly != null && (readonly == 'false' || readonly == false)) {
  82. url = O2ApiManager.instance.getCmsDocumentEditUrl(id) ?? '';
  83. }
  84. for (var element in options.entries) {
  85. OLogger.i('参数 ${element.key} : ${element.value}');
  86. url += '&${element.key}=${Uri.encodeComponent('${element.value}')}';
  87. }
  88. }
  89. if (url.isNotEmpty) {
  90. final uurl = Uri.parse(url);
  91. var host = O2ApiManager.instance.getWebHost();
  92. var domain = uurl.host;
  93. var tokenName = O2ApiManager.instance.tokenName;
  94. var token = O2ApiManager.instance.o2User?.token ?? '';
  95. OLogger.d(
  96. "加载webview cookie,url: $url domain: $domain tokenName: $tokenName token: $token");
  97. CookieManager cookieManager = CookieManager.instance();
  98. await cookieManager.deleteAllCookies();
  99. await cookieManager.setCookie(
  100. url: uurl,
  101. name: tokenName,
  102. value: token,
  103. domain: (domain.isEmpty ? host : domain));
  104. state.url = url;
  105. }
  106. OLogger.d("打开网址: $url");
  107. }
  108. ///
  109. /// 点击appbar 返回按钮
  110. ///
  111. void tapBackBtn() async {
  112. OLogger.d('执行了 tapBackBtn ');
  113. if (await webviewController?.canGoBack() == true) {
  114. webviewController?.goBack();
  115. } else {
  116. closeWindow();
  117. }
  118. }
  119. /// 加载js通道
  120. void setupWebviewJsHandler(InAppWebViewController c) async {
  121. webviewController = c;
  122. webviewController?.addJavaScriptHandler(
  123. handlerName: O2.webviewChannelNameCommonKey,
  124. callback: (msgs) {
  125. OLogger.d(
  126. "js 通信, name: ${O2.webviewChannelNameCommonKey} msg: $msgs");
  127. if (msgs.isNotEmpty) {
  128. String msg = msgs[0] as String? ?? "";
  129. _jsChannelMessageReceived(msg);
  130. }
  131. });
  132. webviewHelper.setupWebviewJsHandler(c);
  133. webviewHelper.setupJsNavigationInterface(this);
  134. }
  135. /// webview 加载进度
  136. void progressChanged(InAppWebViewController c, int p) {
  137. OLogger.d("o2Webview process progress: $p");
  138. // 这里把 inappwebview的 js handler 方式修改成 我们自定义的
  139. if (p == 100 && !isInstallJsName) {
  140. isInstallJsName = true;
  141. // o2android
  142. var js = '''
  143. if (window.flutter_inappwebview && window.flutter_inappwebview.callHandler) {
  144. window.o2android = {};
  145. window.o2android.postMessage = function(message){
  146. window.flutter_inappwebview.callHandler('o2android', message);
  147. };
  148. }
  149. ''';
  150. c.evaluateJavascript(source: js);
  151. OLogger.i("执行o2android转化js完成。。。");
  152. webviewHelper.changeJsHandlerFunName(c);
  153. }
  154. }
  155. /// 打开附件
  156. void _openAttachmentFile(String filePath, String fileName) {
  157. if (filePath.isImageFileName) {
  158. PreviewImagePage.open(filePath, fileName);
  159. } else if (filePath.isVideoFileName) {
  160. VideoPlayerPage.openLocalVideo(filePath, title: fileName);
  161. } else {
  162. channel.openLocalFile(filePath);
  163. }
  164. }
  165. /// 接收js通道返回数据
  166. /// h5上调用js执行flutter这边的原生方法
  167. ///
  168. // void jsChannelMessageReceived(JavascriptMessage message) {
  169. // if (message.message.isNotEmpty) {
  170. void _jsChannelMessageReceived(String message) {
  171. OLogger.d("h5执行原生方法,message: $message");
  172. if (message.isEmpty) {
  173. return;
  174. }
  175. var jsMessage = JsMessage.fromJson(O2Utils.parseStringToJson(message));
  176. switch (jsMessage.type) {
  177. case "closeDocumentWindow":
  178. OLogger.d("关闭表单");
  179. closeWindow();
  180. break;
  181. case "downloadAttachment":
  182. _downloadAttachment(jsMessage.data);
  183. break;
  184. case "uploadAttachment":
  185. _uploadAttachment(jsMessage.data);
  186. break;
  187. case "uploadAttachmentForDatagrid":
  188. _uploadAttachment(jsMessage.data, forGrid: true);
  189. break;
  190. case "replaceAttachment":
  191. _replaceAttachment(jsMessage.data);
  192. break;
  193. case "replaceAttachmentForDatagrid":
  194. _replaceAttachment(jsMessage.data, forGrid: true);
  195. break;
  196. case "uploadImage2FileStorage": // imageclipper 图片上传控件
  197. _uploadImage2FileStorage(jsMessage.data);
  198. break;
  199. case 'openO2Work':
  200. _openWork(jsMessage.data);
  201. break;
  202. case 'createO2CmsDocument':
  203. _createO2CmsDocument(jsMessage.data);
  204. break;
  205. case 'openO2CmsApplication':
  206. _openO2CmsApplication(jsMessage.data);
  207. break;
  208. case 'openO2CmsDocument':
  209. _openO2CmsDocument(jsMessage.data);
  210. break;
  211. default:
  212. OLogger.e('错误的类型,$message');
  213. break;
  214. }
  215. _executeCallbackJs(jsMessage.callback, null);
  216. }
  217. /// 选择图片 或者 拍照
  218. /// 图片控件使用
  219. Future<void> _pickImageByType(int type, Map<String, dynamic> data) async {
  220. XFile? file;
  221. if (type == 0) {
  222. // 相册
  223. file = await _imagePicker.pickImage(source: ImageSource.gallery);
  224. } else if (type == 1) {
  225. // 拍照
  226. if (!await O2Utils.cameraPermission()) {
  227. return;
  228. }
  229. file = await _imagePicker.pickImage(source: ImageSource.camera);
  230. }
  231. if (file != null) {
  232. // var mwfId: String = "",//控件id
  233. // var callback: String = "",//回调函数
  234. // var referencetype: String = "",//上传文件服务器的业务类型名称
  235. // var reference: String = "",//关联业务id
  236. // var fileId: String = ""//上传返回的文件id
  237. String referencetype = data['referencetype'] ?? '';
  238. String reference = data['reference'] ?? '';
  239. String callback = data['callback'] ?? '';
  240. if (referencetype.isEmpty || reference.isEmpty || callback.isEmpty) {
  241. Loading.showError('args_error'.tr);
  242. return;
  243. }
  244. Loading.show();
  245. var id = await FileAssembleService.to.uploadImageWithReferencetype(
  246. referencetype, reference, File(file.path));
  247. if (id != null && id.id != null) {
  248. data['fileId'] = id.id;
  249. final back = json.encode(data);
  250. final js = '$callback(\'$back\')';
  251. OLogger.d('执行js :$js');
  252. await webviewController?.evaluateJavascript(source: js);
  253. Loading.dismiss();
  254. }
  255. }
  256. }
  257. ///
  258. /// 图片上传控件
  259. ///
  260. void _uploadImage2FileStorage(Map<String, dynamic>? data) {
  261. final myContext = Get.context;
  262. if (data != null && myContext != null) {
  263. O2UI.showBottomSheetWithCancel(myContext, [
  264. ListTile(
  265. onTap: () {
  266. Navigator.pop(myContext);
  267. _pickImageByType(0, data);
  268. },
  269. title: Align(
  270. alignment: Alignment.center,
  271. child: Text('album'.tr,
  272. style: Theme.of(myContext).textTheme.bodyMedium),
  273. ),
  274. ),
  275. const Divider(height: 1),
  276. ListTile(
  277. onTap: () {
  278. Navigator.pop(myContext);
  279. _pickImageByType(1, data);
  280. },
  281. title: Align(
  282. alignment: Alignment.center,
  283. child: Text('take_photo'.tr,
  284. style: Theme.of(myContext).textTheme.bodyMedium),
  285. ),
  286. ),
  287. ]);
  288. }
  289. }
  290. ///
  291. /// 下载附件
  292. ///
  293. void _downloadAttachment(Map<String, dynamic>? data) async {
  294. OLogger.d("下载附件");
  295. if (data != null) {
  296. String attachmentId = data["attachmentId"] ?? "";
  297. if (attachmentId.isNotEmpty && docId != null) {
  298. Loading.show();
  299. // 请求附件对象信息
  300. DocAttachmentInfo? info = await CmsAssembleControlService.to
  301. .getAttachmentInfoByDocId(docId!, attachmentId);
  302. if (info != null && info.name != null && info.id != null) {
  303. String? filePath = await O2FilePathUtil.getCmsFileDownloadLocalPath(
  304. info.id!, info.name!);
  305. if (filePath == null || filePath.isEmpty) {
  306. Loading.showError('process_work_download_file_no_path'.tr);
  307. return;
  308. }
  309. var file = File(filePath);
  310. if (file.existsSync()) {
  311. Loading.dismiss();
  312. _openAttachmentFile(filePath, info.name!);
  313. } else {
  314. // 下载附件
  315. var donwloadUrl = CmsAssembleControlService.to
  316. .downloadAttachmentUrl(attachmentId);
  317. try {
  318. await O2HttpClient.instance.downloadFile(donwloadUrl, filePath);
  319. Loading.dismiss();
  320. _openAttachmentFile(filePath, info.name!);
  321. } on Exception catch (e) {
  322. Loading.showError(e.toString());
  323. }
  324. }
  325. } else {
  326. Loading.showError('process_work_download_get_attachmentinfo_fail'.tr);
  327. }
  328. }
  329. }
  330. }
  331. ///
  332. /// 上传附件
  333. ///
  334. void _uploadAttachment(Map<String, dynamic>? data,
  335. {bool forGrid = false}) async {
  336. if (data != null && docId != null) {
  337. String site = data["site"] ?? "";
  338. String param = data["param"] ?? "";
  339. OLogger.d('上传附件 site $site , param $param');
  340. O2Utils.pickerFileOrImage((paths) {
  341. _uploadAttachmentBegin(paths, site, param, forGrid);
  342. }, allowMultiple: true);
  343. }
  344. }
  345. Future<void> _uploadAttachmentBegin(List<String?> paths, String site, String param, bool forGrid) async {
  346. Loading.show();
  347. int errorNumber = 0;
  348. for (var element in paths) {
  349. if (element != null && element.isNotEmpty) {
  350. var resId = await CmsAssembleControlService.to
  351. .uploadAttachment(docId!, site, File(element));
  352. if (resId != null && resId.id != null) {
  353. if (forGrid) {
  354. webviewController?.evaluateJavascript(
  355. source:
  356. "layout.app.appForm.uploadedAttachmentDatagrid(\"$site\", \"${resId.id}\", \"$param\")");
  357. } else {
  358. webviewController?.evaluateJavascript(
  359. source:
  360. "layout.app.appForm.uploadedAttachment(\"$site\", \"${resId.id}\")");
  361. }
  362. OLogger.d('上传附件成功 ${resId.id} ');
  363. } else {
  364. errorNumber++;
  365. }
  366. }
  367. }
  368. if (errorNumber > 0) {
  369. Loading.showError(
  370. 'process_attachment_upload_error'.trArgs(['$errorNumber']));
  371. } else {
  372. Loading.dismiss();
  373. }
  374. }
  375. ///
  376. /// 替换附件
  377. ///
  378. void _replaceAttachment(Map<String, dynamic>? data, {bool forGrid = false}) async {
  379. if (data != null && docId != null) {
  380. String site = data["site"] ?? "";
  381. String attachmentId = data["attachmentId"] ?? "";
  382. String param = data["param"] ?? "";
  383. OLogger.d('替换附件 site $site , attachmentId $attachmentId , param $param');
  384. O2Utils.pickerFileOrImage((paths) {
  385. _replaceAttachmentBegin(paths, attachmentId, site, param, forGrid);
  386. });
  387. }
  388. }
  389. Future<void> _replaceAttachmentBegin(List<String?> paths, String attachmentId, String site, String param, bool forGrid) async {
  390. if (paths.isEmpty) {
  391. return;
  392. }
  393. String path = paths[0] ?? '';
  394. if (path.isEmpty) {
  395. return;
  396. }
  397. Loading.show();
  398. OLogger.d('选择了文件:$path');
  399. var resId = await ProcessSurfaceService.to
  400. .replaceAttachment(docId!, attachmentId, File(path));
  401. if (resId != null && resId.id != null) {
  402. if (forGrid) {
  403. webviewController?.evaluateJavascript(
  404. source:
  405. "layout.app.appForm.replacedAttachmentDatagrid(\"$site\", \"${resId.id}\", \"$param\")");
  406. } else {
  407. webviewController?.evaluateJavascript(
  408. source:
  409. "layout.app.appForm.replacedAttachment(\"$site\", \"${resId.id}\")");
  410. }
  411. OLogger.d('替换附件成功 ${resId.id} ');
  412. Loading.dismiss();
  413. }
  414. }
  415. /// 打开工作
  416. /// workId: String, workCompletedId: String, title: String
  417. void _openWork(Map<String, dynamic>? data) {
  418. OLogger.d('===> _openWork, data: $data');
  419. if (data != null) {
  420. String workid = data['workId'] ?? '';
  421. if (workid.isEmpty) {
  422. workid = data['workCompletedId'] ?? '';
  423. }
  424. String darftId = data['draftId'] ?? '';
  425. if (workid.isNotEmpty) {
  426. ProcessWebviewPage.open(workid,
  427. title: data['title'] ?? 'process_work_no_title_no_process'.tr);
  428. } else if (darftId.isNotEmpty) {
  429. ProcessWebviewPage.openDraftById(darftId,
  430. title: data['title'] ?? 'process_work_no_title_no_process'.tr);
  431. }
  432. }
  433. }
  434. /// 打开信息文档
  435. /// docId: String, title: String, options: Map<String, dynamic>?
  436. void _openO2CmsDocument(Map<String, dynamic>? data) {
  437. if (data != null) {
  438. String docId = data['docId'] ?? '';
  439. if (docId.isNotEmpty) {
  440. CmsDocumentPage.open(docId,
  441. title: data['title'] ?? '', options: data['options']);
  442. }
  443. }
  444. }
  445. /// 打开信息中心
  446. /// appId: String, title: String
  447. void _openO2CmsApplication(Map<String, dynamic>? data) async {
  448. if (data != null && data['appId'] != null && data['appId'] is String) {
  449. var list =
  450. await CmsAssembleControlService.to.listAppWithCategoryUserCanView();
  451. if (list != null) {
  452. var app = list.firstWhereOrNull((element) =>
  453. element.id == data['appId'] ||
  454. element.appAlias == data['appId'] ||
  455. element.appName == data['appId']);
  456. if (app != null) {
  457. CmsAppPage.open(app); // 打开对应的
  458. return;
  459. }
  460. }
  461. }
  462. // 没有参数 直接打开cms
  463. Get.toNamed(O2OARoutes.appCms);
  464. }
  465. ///
  466. /// 创建文档
  467. /// * 创建文档 目前只有 column 和 category 有效果
  468. /* {
  469. "column" : column, //(string)可选,内容管理应用(栏目)的名称、别名或ID
  470. "category" : category, //(string)可选,要创建的文档所属的分类的名称、别名或ID
  471. "data" : data, //(json object)可选,创建文档时默认的业务数据
  472. "identity" : identity, //(string)可选,创建文档所使用的身份。如果此参数为空,且当前人有多个身份的情况下,会弹出身份选择对话框;否则使用默认身份。
  473. "callback" : callback, //(funcation)可选,文档创建后的回调函数。
  474. "target" : target, //(boolean)可选,为true时,在当前页面打开创建的文档;否则打开新窗口。默认false。
  475. "latest" : latest, //(boolean)可选,为true时,如果当前用户已经创建了此分类的文档,并且没有发布过,直接调用此文档为新文档;否则创建一个新文档。默认true。
  476. "selectColumnEnable" : selectColumnEnable, //(boolean)可选,是否可以选择应用和分类进行创建文档。有category参数时为默认false,否则默认为true。
  477. "ignoreTitle" : ignoreTitle //(boolean)可选,值为false时,创建的时候需要强制填写标题,默认为false。
  478. "restrictToColumn" : restrictToColumn //(boolean)可选,值为true时,会限制在传入的栏目中选择分类,默认为false。
  479. } */
  480. ///
  481. void _createO2CmsDocument(Map<String, dynamic>? data) async {
  482. OLogger.d('===> _createO2CmsDocument, data: $data');
  483. _app = null;
  484. _category = null;
  485. if (data != null) {
  486. _cmsMessageData = data;
  487. var categoryId = _cmsMessageData?['category'];
  488. if (categoryId != null && categoryId is String && categoryId.isNotEmpty) {
  489. // 根据分类id查询 分类和应用
  490. _category = await CmsAssembleControlService.to.getCategory(categoryId);
  491. if (_category != null && _category?.appId != null && _app == null) {
  492. _app = await CmsAssembleControlService.to.getApp(_category!.appId!);
  493. }
  494. } else {
  495. var appId = _cmsMessageData?['column'];
  496. if (appId != null && appId is String && appId.isNotEmpty) {
  497. // 只有应用id的情况 弹出分类选择器
  498. _app = await CmsAssembleControlService.to
  499. .getAppCanPublishCategories(appId);
  500. if (_app != null &&
  501. _app?.wrapOutCategoryList != null &&
  502. _app!.wrapOutCategoryList!.isNotEmpty) {
  503. var cList = _app!.wrapOutCategoryList!;
  504. if (cList.length == 1) {
  505. _category = cList[0];
  506. } else {
  507. _showCmsCategoryChoose(cList);
  508. return;
  509. }
  510. }
  511. }
  512. }
  513. }
  514. // 传入参数不足,选择分类
  515. if (_app == null || _category == null) {
  516. var category = await Get.toNamed(O2OARoutes.appCmsCategoryPicker);
  517. if (category != null && category is CmsCategoryData) {
  518. OLogger.d('选择了分类: ${category.toJson()}');
  519. _app = category.withApp;
  520. _category = category;
  521. }
  522. }
  523. _startCreateDocument();
  524. }
  525. /// 选择分类
  526. void _showCmsCategoryChoose(List<CmsCategoryData> list) {
  527. final c = Get.context;
  528. if (c != null) {
  529. O2UI.showBottomSheetWithCancel(
  530. c,
  531. list
  532. .map((e) => ListTile(
  533. onTap: () {
  534. Navigator.pop(c);
  535. _category = e;
  536. _startCreateDocument();
  537. },
  538. title: Align(
  539. alignment: Alignment.center,
  540. child: Text(e.categoryName ?? '',
  541. style: Theme.of(c).textTheme.bodyMedium),
  542. ),
  543. ))
  544. .toList());
  545. }
  546. }
  547. ///
  548. /// 参数查询完成后开始创建文档
  549. /// _app、_category 都赋值后
  550. ///
  551. void _startCreateDocument() async {
  552. if (_app == null || _category == null) {
  553. Loading.toast('cms_create_document_no_args'.tr);
  554. return;
  555. }
  556. OLogger.d('创建文档,app:${_app?.toJson()}');
  557. OLogger.d('创建文档,category:${_category?.toJson()}');
  558. final config = _app?.config ?? '{}';
  559. final configMap = O2Utils.parseStringToJson(config);
  560. final messageData = _cmsMessageData ?? {};
  561. bool ignoreTitle = false; // 是否忽略标题
  562. bool latest = true; // 是否查询草稿
  563. if (messageData.containsKey('ignoreTitle')) {
  564. ignoreTitle = messageData['ignoreTitle'] ?? false;
  565. } else if (configMap.containsKey('ignoreTitle')) {
  566. ignoreTitle = configMap['ignoreTitle'] ?? false;
  567. }
  568. if (messageData.containsKey('latest')) {
  569. latest = messageData['latest'] ?? true;
  570. } else if (configMap.containsKey('latest')) {
  571. latest = configMap['latest'] ?? true;
  572. }
  573. if (latest) {
  574. var drafts =
  575. await CmsAssembleControlService.to.listDocumentDraft(_category!.id!);
  576. if (drafts != null && drafts.isNotEmpty) {
  577. OLogger.d('有草稿。。。。');
  578. CmsDocumentPage.open(drafts[0].id!,
  579. title: drafts[0].title ?? '', options: {"readonly": false});
  580. return;
  581. }
  582. }
  583. CreateFormPage.startCmsDoc(ignoreTitle, category: _category!, cmsData: messageData['data']);
  584. }
  585. ///
  586. /// 如果有callback函数 就执行
  587. ///
  588. void _executeCallbackJs(String? callback, dynamic result) {
  589. if (callback != null && callback.isNotEmpty) {
  590. if (result != null) {
  591. webviewController?.evaluateJavascript(source: '$callback($result)');
  592. } else {
  593. webviewController?.evaluateJavascript(source: '$callback()');
  594. }
  595. }
  596. }
  597. /// 复制当前链接
  598. void copyLink() async {
  599. final url = await webviewController?.getUrl();
  600. if (url != null) {
  601. Clipboard.setData(ClipboardData(text: url.toString()));
  602. Loading.toast('im_chat_success_copy'.tr);
  603. }
  604. }
  605. }