Template.php 13 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371
  1. <?php
  2. namespace app\api\controller\ps;
  3. use app\common\controller\Api;
  4. use app\common\library\ps\FactoryContext;
  5. use app\common\library\ps\FactoryPerm;
  6. use app\common\library\ps\MarketPublisher;
  7. use app\common\model\ps\MarketGoods;
  8. use app\common\model\ps\Template as TemplateModel;
  9. /**
  10. * 模板接口
  11. */
  12. class Template extends Api
  13. {
  14. protected $noNeedRight = '*';
  15. /**
  16. * @var TemplateModel
  17. */
  18. protected $model = null;
  19. public function _initialize()
  20. {
  21. parent::_initialize();
  22. if (!FactoryContext::id()) {
  23. $this->error('账号未绑定工厂');
  24. }
  25. $this->model = new TemplateModel;
  26. $action = strtolower($this->request->action());
  27. if ($action === 'index' || $action === 'info') {
  28. if (!FactoryPerm::canAny(['template.view', 'print.do'])) {
  29. $this->error('没有权限查看模板');
  30. }
  31. } else {
  32. $map = [
  33. 'saveschema' => 'template.edit',
  34. 'save_schema' => 'template.edit',
  35. 'add' => 'template.edit',
  36. 'edit' => 'template.edit',
  37. 'create_blank' => 'template.edit',
  38. 'copy' => 'template.edit',
  39. 'del' => 'template.delete',
  40. ];
  41. if (isset($map[$action]) && FactoryPerm::deny($map[$action])) {
  42. $this->error('没有权限:' . FactoryPerm::label($map[$action]));
  43. }
  44. }
  45. }
  46. /**
  47. * 本厂模板库
  48. */
  49. public function index()
  50. {
  51. $limit = $this->request->request('limit/d', 50);
  52. $printable = $this->request->request('printable/d', 0);
  53. $query = $this->model->where('status', 'normal')->order('id desc');
  54. if ($printable) {
  55. $query->printable();
  56. }
  57. $list = $query->paginate($limit);
  58. $rows = [];
  59. foreach ($list->items() as $item) {
  60. $rows[] = $this->formatRow($item);
  61. }
  62. $this->attachMarket($rows);
  63. $this->success('', ['total' => $list->total(), 'rows' => $rows]);
  64. }
  65. /**
  66. * 详情
  67. */
  68. public function info()
  69. {
  70. $id = $this->request->request('id/d');
  71. $row = $this->model->find($id);
  72. if (!$row) {
  73. $this->error(__('No Results were found'));
  74. }
  75. $this->success('', $this->formatRow($row, true));
  76. }
  77. /**
  78. * 封面用站内相对路径,工厂端 Vite 才能代理到 /uploads。
  79. * @param mixed $item
  80. * @param bool $withMarket
  81. * @return array
  82. */
  83. protected function formatRow($item, $withMarket = false)
  84. {
  85. $row = is_array($item) ? $item : $item->toArray();
  86. $cover = isset($row['cover']) ? trim((string)$row['cover']) : '';
  87. if ($cover === '' && !empty($row['id'])) {
  88. $versionId = (int)($row['current_version_id'] ?? 0);
  89. if ($versionId > 0) {
  90. $schema = \think\Db::name('ps_template_version')->where('id', $versionId)->value('schema_json');
  91. $decoded = $schema ? json_decode($schema, true) : [];
  92. if (is_array($decoded)) {
  93. $cover = (string)($decoded['background'] ?? $decoded['file_url'] ?? $decoded['image'] ?? '');
  94. }
  95. }
  96. }
  97. $row['cover'] = $cover;
  98. $schemaJson = '';
  99. if (!empty($row['current_version_id'])) {
  100. $schemaJson = (string)\think\Db::name('ps_template_version')->where('id', (int)$row['current_version_id'])->value('schema_json');
  101. }
  102. $schema = \app\common\library\ps\PrintPlanner::decodeSchema($schemaJson, $cover);
  103. $row['schema'] = $schema;
  104. $row['schema_json'] = json_encode($schema, JSON_UNESCAPED_UNICODE);
  105. $row['cover_url'] = $this->coverUrl($schema['background'] ?: $cover);
  106. $row['field_catalog'] = \app\common\library\ps\PrintPlanner::fieldCatalog();
  107. $row['can_delete'] = (int)$row['is_system'] !== 1 && (int)($row['factory_id'] ?? 0) === (int)FactoryContext::id();
  108. $row['can_publish'] = (int)$row['is_system'] !== 1
  109. && ($row['source'] ?? '') !== 'market'
  110. && strpos((string)($row['license_type'] ?? ''), 'market_') !== 0;
  111. if ($withMarket) {
  112. $rows = [$row];
  113. $this->attachMarket($rows);
  114. return $rows[0];
  115. }
  116. return $row;
  117. }
  118. /**
  119. * @param array $rows
  120. */
  121. protected function attachMarket(array &$rows)
  122. {
  123. $ids = [];
  124. foreach ($rows as $row) {
  125. if (!empty($row['id'])) {
  126. $ids[] = (int)$row['id'];
  127. }
  128. }
  129. $ids = array_values(array_unique($ids));
  130. $map = [];
  131. if ($ids) {
  132. $goods = (new MarketGoods())
  133. ->where('factory_id', FactoryContext::id())
  134. ->where('template_id', 'in', $ids)
  135. ->select();
  136. foreach ($goods as $item) {
  137. $g = is_array($item) ? $item : $item->toArray();
  138. $map[(int)$g['template_id']] = [
  139. 'id' => (int)$g['id'],
  140. 'status' => $g['status'],
  141. 'price_single' => (int)$g['price_single'],
  142. 'price_buyout' => (int)$g['price_buyout'],
  143. 'title' => $g['title'],
  144. 'intro' => $g['intro'],
  145. 'on_sale' => $g['status'] === 'on_sale',
  146. ];
  147. }
  148. }
  149. foreach ($rows as &$row) {
  150. $row['market'] = isset($map[(int)$row['id']]) ? $map[(int)$row['id']] : null;
  151. }
  152. unset($row);
  153. }
  154. /**
  155. * @param string $path
  156. * @return string
  157. */
  158. protected function coverUrl($path)
  159. {
  160. $path = trim((string)$path);
  161. if ($path === '') {
  162. return '';
  163. }
  164. if (preg_match('#^(https?:)?//#i', $path) || strpos($path, 'data:') === 0) {
  165. return $path;
  166. }
  167. return '/' . ltrim(str_replace('\\', '/', $path), '/');
  168. }
  169. /**
  170. * 保存套打坐标与文字(生成新版本)
  171. */
  172. public function saveSchema()
  173. {
  174. $id = $this->request->post('id/d');
  175. $row = $this->model->find($id);
  176. if (!$row) {
  177. $this->error(__('No Results were found'));
  178. }
  179. if ((int)$row['is_system'] === 1) {
  180. $this->error('官方模板不可修改');
  181. }
  182. $name = trim((string)$this->request->post('name', ''));
  183. $schema = $this->request->post('schema/a');
  184. if (!$schema) {
  185. $raw = $this->request->post('schema_json', '', null);
  186. $schema = json_decode((string)$raw, true);
  187. }
  188. if (!is_array($schema)) {
  189. $this->error('排版数据不正确');
  190. }
  191. $schema = \app\common\library\ps\PrintPlanner::decodeSchema(json_encode($schema, JSON_UNESCAPED_UNICODE), $row['cover']);
  192. if ($name !== '') {
  193. $schema['name'] = $name;
  194. }
  195. $next = (int)\think\Db::name('ps_template_version')->where('template_id', $row->id)->max('version') + 1;
  196. if ($next < 1) {
  197. $next = 1;
  198. }
  199. $ver = new \app\common\model\ps\TemplateVersion();
  200. $ver->allowField(true)->save([
  201. 'template_id' => $row->id,
  202. 'version' => $next,
  203. 'schema_json' => json_encode($schema, JSON_UNESCAPED_UNICODE),
  204. 'remark' => '页面调整',
  205. ]);
  206. $save = [
  207. 'current_version_id' => $ver->id,
  208. ];
  209. if ($name !== '') {
  210. $save['name'] = $name;
  211. }
  212. if (!empty($schema['background'])) {
  213. $save['cover'] = $schema['background'];
  214. }
  215. $row->allowField(true)->save($save);
  216. $this->success('已保存', ['id' => (int)$row->id, 'version_id' => (int)$ver->id]);
  217. }
  218. /**
  219. * 保存套打坐标与文字
  220. */
  221. public function save_schema()
  222. {
  223. return $this->saveSchema();
  224. }
  225. /**
  226. * 添加(保存到本厂模板库)
  227. */
  228. public function add()
  229. {
  230. $params = $this->request->post();
  231. if (!$params) {
  232. $this->error(__('Parameter %s can not be empty', ''));
  233. }
  234. $params['creator_user_id'] = $this->auth->id;
  235. $params['is_system'] = 0;
  236. $params['license_type'] = isset($params['license_type']) ? $params['license_type'] : 'self';
  237. unset($params['id'], $params['factory_id']);
  238. $this->model->allowField(true)->save($params);
  239. $this->success('', ['id' => $this->model->id]);
  240. }
  241. /**
  242. * 编辑
  243. */
  244. public function edit()
  245. {
  246. $id = $this->request->post('id/d');
  247. $row = $this->model->find($id);
  248. if (!$row) {
  249. $this->error(__('No Results were found'));
  250. }
  251. if ((int)$row['is_system'] === 1) {
  252. $this->error('官方模板不可修改,请先复制到本厂模板库');
  253. }
  254. $params = $this->request->post();
  255. unset($params['id'], $params['factory_id'], $params['is_system']);
  256. $row->allowField(true)->save($params);
  257. $this->success();
  258. }
  259. /**
  260. * 删除
  261. */
  262. public function del()
  263. {
  264. $id = $this->request->post('id/d');
  265. $row = $this->model->find($id);
  266. if (!$row) {
  267. $this->error(__('No Results were found'));
  268. }
  269. if ((int)$row['is_system'] === 1) {
  270. $this->error('官方模板不可删除');
  271. }
  272. \think\Db::name('ps_template_version')->where('template_id', $row->id)->delete();
  273. \think\Db::name('ps_ai_job')->where('template_id', $row->id)->update(['template_id' => 0]);
  274. MarketPublisher::offByTemplate($row->id, FactoryContext::id());
  275. $row->delete();
  276. $this->success('已删除');
  277. }
  278. /**
  279. * 从空白纸新建可套打模板
  280. */
  281. public function create_blank()
  282. {
  283. $name = trim((string)$this->request->post('name', ''));
  284. if ($name === '') {
  285. $name = '空白模板 ' . date('m-d H:i');
  286. }
  287. $schema = [
  288. 'name' => $name,
  289. 'mode' => 'compose',
  290. 'page' => ['w' => 210, 'h' => 297, 'background' => '#ffffff'],
  291. 'background' => '',
  292. 'file_url' => '',
  293. 'elements' => [],
  294. 'source' => 'manual',
  295. ];
  296. $row = new TemplateModel();
  297. $row->allowField(true)->save([
  298. 'creator_user_id' => $this->auth->id,
  299. 'name' => $name,
  300. 'cover' => '',
  301. 'source' => 'manual',
  302. 'license_type' => 'self',
  303. 'locked' => 0,
  304. 'is_system' => 0,
  305. 'status' => 'normal',
  306. ]);
  307. $ver = new \app\common\model\ps\TemplateVersion();
  308. $ver->allowField(true)->save([
  309. 'template_id' => $row->id,
  310. 'version' => 1,
  311. 'schema_json' => json_encode($schema, JSON_UNESCAPED_UNICODE),
  312. 'remark' => '空白新建',
  313. ]);
  314. $row->save(['current_version_id' => $ver->id]);
  315. $this->success('已创建空白模板', ['id' => (int)$row->id]);
  316. }
  317. /**
  318. * 复制为本厂新模板
  319. */
  320. public function copy()
  321. {
  322. $id = $this->request->post('id/d');
  323. $row = $this->model->find($id);
  324. if (!$row) {
  325. $this->error(__('No Results were found'));
  326. }
  327. $schemaJson = \app\common\library\ps\PrintPlanner::schemaJson($row);
  328. $schema = \app\common\library\ps\PrintPlanner::decodeSchema($schemaJson, $row['cover']);
  329. $name = trim((string)$row['name']) . ' 副本';
  330. $schema['name'] = $name;
  331. $dup = new TemplateModel();
  332. $dup->allowField(true)->save([
  333. 'creator_user_id' => $this->auth->id,
  334. 'name' => $name,
  335. 'cover' => (string)$row['cover'],
  336. 'source' => 'manual',
  337. 'license_type' => 'self',
  338. 'locked' => 0,
  339. 'source_template_id' => (int)$row->id,
  340. 'source_version_id' => (int)$row['current_version_id'],
  341. 'is_system' => 0,
  342. 'status' => 'normal',
  343. ]);
  344. $ver = new \app\common\model\ps\TemplateVersion();
  345. $ver->allowField(true)->save([
  346. 'template_id' => $dup->id,
  347. 'version' => 1,
  348. 'schema_json' => json_encode($schema, JSON_UNESCAPED_UNICODE),
  349. 'remark' => '复制模板',
  350. ]);
  351. $dup->save(['current_version_id' => $ver->id]);
  352. $this->success('已复制', ['id' => (int)$dup->id]);
  353. }
  354. }