Product.php 42 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063106410651066106710681069107010711072107310741075107610771078107910801081108210831084108510861087
  1. <?php
  2. /**
  3. * 易优CMS
  4. * ============================================================================
  5. * 版权所有 2016-2028 海南赞赞网络科技有限公司,并保留所有权利。
  6. * 网站地址: http://www.eyoucms.com
  7. * ----------------------------------------------------------------------------
  8. * 如果商业用途务必到官方购买正版授权, 以免引起不必要的法律纠纷.
  9. * ============================================================================
  10. * Author: 小虎哥 <1105415366@qq.com>
  11. * Date: 2018-4-3
  12. */
  13. namespace app\admin\controller;
  14. use think\Page;
  15. use think\Db;
  16. use app\common\logic\ArctypeLogic;
  17. use app\admin\logic\ProductLogic;
  18. use app\admin\logic\ProductSpecLogic; // 用于产品规格逻辑功能处理
  19. class Product extends Base
  20. {
  21. // 模型标识
  22. public $nid = 'product';
  23. // 模型ID
  24. public $channeltype = '';
  25. // 表单类型
  26. public $attrInputTypeArr = array();
  27. public function _initialize()
  28. {
  29. parent::_initialize();
  30. $channeltype_list = config('global.channeltype_list');
  31. $this->channeltype = $channeltype_list[$this->nid];
  32. empty($this->channeltype) && $this->channeltype = 2;
  33. $this->attrInputTypeArr = config('global.attr_input_type_arr');
  34. $this->assign('nid', $this->nid);
  35. $this->assign('channeltype', $this->channeltype);
  36. }
  37. /**
  38. * 文章列表
  39. */
  40. public function index()
  41. {
  42. $assign_data = array();
  43. $condition = array();
  44. // 获取到所有GET参数
  45. $param = input('param.');
  46. $flag = input('flag/s');
  47. $typeid = input('typeid/d', 0);
  48. $begin = strtotime(input('add_time_begin'));
  49. $end = strtotime(input('add_time_end'));
  50. // 应用搜索条件
  51. foreach (['keywords','typeid','flag','is_release'] as $key) {
  52. if (isset($param[$key]) && $param[$key] !== '') {
  53. if ($key == 'keywords') {
  54. $condition['a.title'] = array('LIKE', "%{$param[$key]}%");
  55. } else if ($key == 'typeid') {
  56. $typeid = $param[$key];
  57. $hasRow = model('Arctype')->getHasChildren($typeid);
  58. $typeids = get_arr_column($hasRow, 'id');
  59. /*权限控制 by 小虎哥*/
  60. $admin_info = session('admin_info');
  61. if (0 < intval($admin_info['role_id'])) {
  62. $auth_role_info = $admin_info['auth_role_info'];
  63. if(! empty($auth_role_info)){
  64. if(! empty($auth_role_info['permission']['arctype'])){
  65. if (!empty($typeid)) {
  66. $typeids = array_intersect($typeids, $auth_role_info['permission']['arctype']);
  67. }
  68. }
  69. }
  70. }
  71. /*--end*/
  72. $condition['a.typeid'] = array('IN', $typeids);
  73. } else if ($key == 'flag') {
  74. if ('is_release' == $param[$key]) {
  75. $condition['a.users_id'] = array('gt', 0);
  76. } else {
  77. $condition['a.'.$param[$key]] = array('eq', 1);
  78. }
  79. // } else if ($key == 'is_release') {
  80. // if (0 < intval($param[$key])) {
  81. // $condition['a.users_id'] = array('gt', intval($param[$key]));
  82. // }
  83. } else {
  84. $condition['a.'.$key] = array('eq', $param[$key]);
  85. }
  86. }
  87. }
  88. /*权限控制 by 小虎哥*/
  89. $admin_info = session('admin_info');
  90. if (0 < intval($admin_info['role_id'])) {
  91. $auth_role_info = $admin_info['auth_role_info'];
  92. if(! empty($auth_role_info)){
  93. if(isset($auth_role_info['only_oneself']) && 1 == $auth_role_info['only_oneself']){
  94. $condition['a.admin_id'] = $admin_info['admin_id'];
  95. }
  96. }
  97. }
  98. /*--end*/
  99. // 时间检索
  100. if ($begin > 0 && $end > 0) {
  101. $condition['a.add_time'] = array('between',"$begin,$end");
  102. } else if ($begin > 0) {
  103. $condition['a.add_time'] = array('egt', $begin);
  104. } else if ($end > 0) {
  105. $condition['a.add_time'] = array('elt', $end);
  106. }
  107. // 模型ID
  108. $condition['a.channel'] = array('eq', $this->channeltype);
  109. // 多语言
  110. $condition['a.lang'] = array('eq', $this->admin_lang);
  111. // 回收站
  112. $condition['a.is_del'] = array('eq', 0);
  113. /*自定义排序*/
  114. $orderby = input('param.orderby/s');
  115. $orderway = input('param.orderway/s');
  116. if (!empty($orderby)) {
  117. $orderby = "a.{$orderby} {$orderway}";
  118. $orderby .= ", a.aid desc";
  119. } else {
  120. $orderby = "a.aid desc";
  121. }
  122. /*end*/
  123. /**
  124. * 数据查询,搜索出主键ID的值
  125. */
  126. $count = DB::name('archives')->alias('a')->where($condition)->count('aid');// 查询满足要求的总记录数
  127. $Page = new Page($count, config('paginate.list_rows'));// 实例化分页类 传入总记录数和每页显示的记录数
  128. $list = DB::name('archives')
  129. ->field("a.aid")
  130. ->alias('a')
  131. ->where($condition)
  132. ->order($orderby)
  133. ->limit($Page->firstRow.','.$Page->listRows)
  134. ->getAllWithIndex('aid');
  135. /**
  136. * 完善数据集信息
  137. * 在数据量大的情况下,经过优化的搜索逻辑,先搜索出主键ID,再通过ID将其他信息补充完整;
  138. */
  139. if ($list) {
  140. $aids = array_keys($list);
  141. $fields = "b.*, a.*, a.aid as aid";
  142. $row = DB::name('archives')
  143. ->field($fields)
  144. ->alias('a')
  145. ->join('__ARCTYPE__ b', 'a.typeid = b.id', 'LEFT')
  146. ->where('a.aid', 'in', $aids)
  147. ->getAllWithIndex('aid');
  148. foreach ($list as $key => $val) {
  149. $row[$val['aid']]['arcurl'] = get_arcurl($row[$val['aid']]);
  150. $row[$val['aid']]['litpic'] = handle_subdir_pic($row[$val['aid']]['litpic']); // 支持子目录
  151. $list[$key] = $row[$val['aid']];
  152. }
  153. }
  154. $show = $Page->show(); // 分页显示输出
  155. $assign_data['page'] = $show; // 赋值分页输出
  156. $assign_data['list'] = $list; // 赋值数据集
  157. $assign_data['pager'] = $Page; // 赋值分页对象
  158. // 栏目ID
  159. $assign_data['typeid'] = $typeid; // 栏目ID
  160. /*当前栏目信息*/
  161. $arctype_info = array();
  162. if ($typeid > 0) {
  163. $arctype_info = M('arctype')->field('typename')->find($typeid);
  164. }
  165. $assign_data['arctype_info'] = $arctype_info;
  166. /*--end*/
  167. /*选项卡*/
  168. $tab = input('param.tab/d', 3);
  169. $assign_data['tab'] = $tab;
  170. /*--end*/
  171. $this->assign($assign_data);
  172. return $this->fetch();
  173. }
  174. /**
  175. * 添加
  176. */
  177. public function add()
  178. {
  179. if (IS_POST) {
  180. $post = input('post.');
  181. $content = input('post.addonFieldExt.content', '', null);
  182. // 根据标题自动提取相关的关键字
  183. $seo_keywords = $post['seo_keywords'];
  184. if (!empty($seo_keywords)) {
  185. $seo_keywords = str_replace(',', ',', $seo_keywords);
  186. } else {
  187. // $seo_keywords = get_split_word($post['title'], $content);
  188. }
  189. // 自动获取内容第一张图片作为封面图
  190. $is_remote = !empty($post['is_remote']) ? $post['is_remote'] : 0;
  191. $litpic = '';
  192. if ($is_remote == 1) {
  193. $litpic = $post['litpic_remote'];
  194. } else {
  195. $litpic = $post['litpic_local'];
  196. }
  197. if (empty($litpic)) {
  198. $litpic = get_html_first_imgurl($content);
  199. }
  200. $post['litpic'] = $litpic;
  201. /*是否有封面图*/
  202. if (empty($post['litpic'])) {
  203. $is_litpic = 0; // 无封面图
  204. } else {
  205. $is_litpic = 1; // 有封面图
  206. }
  207. // SEO描述
  208. $seo_description = '';
  209. if (empty($post['seo_description']) && !empty($content)) {
  210. $seo_description = @msubstr(checkStrHtml($content), 0, config('global.arc_seo_description_length'), false);
  211. } else {
  212. $seo_description = $post['seo_description'];
  213. }
  214. // 外部链接跳转
  215. $jumplinks = '';
  216. $is_jump = isset($post['is_jump']) ? $post['is_jump'] : 0;
  217. if (intval($is_jump) > 0) {
  218. $jumplinks = $post['jumplinks'];
  219. }
  220. // 模板文件,如果文档模板名与栏目指定的一致,默认就为空。让它跟随栏目的指定而变
  221. if ($post['type_tempview'] == $post['tempview']) {
  222. unset($post['type_tempview']);
  223. unset($post['tempview']);
  224. }
  225. //处理自定义文件名,仅由字母数字下划线和短横杆组成,大写强制转换为小写
  226. if (!empty($post['htmlfilename'])) {
  227. $post['htmlfilename'] = preg_replace("/[^a-zA-Z0-9_-]+/", "", $post['htmlfilename']);
  228. $post['htmlfilename'] = strtolower($post['htmlfilename']);
  229. //判断是否存在相同的自定义文件名
  230. $filenameCount = Db::name('archives')->where([
  231. 'htmlfilename' => $post['htmlfilename'],
  232. ])->count();
  233. if (!empty($filenameCount)) {
  234. $this->error("自定义文件名已存在,请重新设置!");
  235. }
  236. }
  237. // 产品类型
  238. if (!empty($post['prom_type'])) {
  239. if ($post['prom_type_vir'] == 2) {
  240. $post['netdisk_url'] = trim($post['netdisk_url']);
  241. if (empty($post['netdisk_url'])) {
  242. $this->error("网盘地址不能为空!");
  243. }
  244. $post['prom_type'] = 2;
  245. } else if ($post['prom_type_vir'] == 3) {
  246. $post['text_content'] = trim($post['text_content']);
  247. if (empty($post['text_content'])) {
  248. $this->error("虚拟文本内容不能为空!");
  249. }
  250. $post['prom_type'] = 3;
  251. }
  252. }
  253. // --存储数据
  254. $newData = array(
  255. 'typeid'=> empty($post['typeid']) ? 0 : $post['typeid'],
  256. 'channel' => $this->channeltype,
  257. 'is_b' => empty($post['is_b']) ? 0 : $post['is_b'],
  258. 'is_head' => empty($post['is_head']) ? 0 : $post['is_head'],
  259. 'is_special' => empty($post['is_special']) ? 0 : $post['is_special'],
  260. 'is_recom' => empty($post['is_recom']) ? 0 : $post['is_recom'],
  261. 'is_jump' => $is_jump,
  262. 'is_litpic' => $is_litpic,
  263. 'jumplinks' => $jumplinks,
  264. 'seo_keywords' => $seo_keywords,
  265. 'seo_description' => $seo_description,
  266. 'admin_id' => session('admin_info.admin_id'),
  267. 'stock_show' => empty($post['stock_show']) ? 0 : $post['stock_show'],
  268. 'lang' => $this->admin_lang,
  269. 'sort_order' => 100,
  270. 'add_time' => strtotime($post['add_time']),
  271. 'update_time' => strtotime($post['add_time']),
  272. );
  273. $data = array_merge($post, $newData);
  274. $aid = Db::name('archives')->insertGetId($data);
  275. $_POST['aid'] = $aid;
  276. if ($aid) {
  277. // ---------后置操作
  278. model('Product')->afterSave($aid, $data, 'add');
  279. // ---------end
  280. // 添加产品规格
  281. model('ProductSpecPreset')->ProductSpecInsertAll($aid, $data);
  282. adminLog('新增产品:'.$data['title']);
  283. //虚拟商品保存
  284. if (!empty($post['prom_type']) && in_array($post['prom_type'], [2,3])) {
  285. model('ProductNetdisk')->saveProductNetdisk($aid, $data);
  286. }
  287. // 生成静态页面代码
  288. $successData = [
  289. 'aid' => $aid,
  290. 'tid' => $post['typeid'],
  291. ];
  292. $this->success("操作成功!", null, $successData);
  293. exit;
  294. }
  295. $this->error("操作失败!");
  296. exit;
  297. }
  298. $typeid = input('param.typeid/d', 0);
  299. $assign_data['typeid'] = $typeid; // 栏目ID
  300. // 栏目信息
  301. $arctypeInfo = Db::name('arctype')->find($typeid);
  302. /*允许发布文档列表的栏目*/
  303. $arctype_html = allow_release_arctype($typeid, array($this->channeltype));
  304. $assign_data['arctype_html'] = $arctype_html;
  305. /*--end*/
  306. /*自定义字段*/
  307. $addonFieldExtList = model('Field')->getChannelFieldList($this->channeltype);
  308. $channelfieldBindRow = Db::name('channelfield_bind')->where([
  309. 'typeid' => ['IN', [0,$typeid]],
  310. ])->column('field_id');
  311. if (!empty($channelfieldBindRow)) {
  312. foreach ($addonFieldExtList as $key => $val) {
  313. if (!in_array($val['id'], $channelfieldBindRow)) {
  314. unset($addonFieldExtList[$key]);
  315. }
  316. }
  317. }
  318. $assign_data['addonFieldExtList'] = $addonFieldExtList;
  319. $assign_data['aid'] = 0;
  320. /*--end*/
  321. /*可控制的字段列表*/
  322. $assign_data['ifcontrolRow'] = Db::name('channelfield')->field('id,name')->where([
  323. 'channel_id' => $this->channeltype,
  324. 'ifmain' => 1,
  325. 'ifeditable' => 1,
  326. 'ifcontrol' => 0,
  327. 'status' => 1,
  328. ])->getAllWithIndex('name');
  329. // 阅读权限
  330. $arcrank_list = get_arcrank_list();
  331. $assign_data['arcrank_list'] = $arcrank_list;
  332. /*产品参数*/
  333. $assign_data['canshu'] = $this->ajax_get_attr_input($typeid);
  334. /*--end*/
  335. /*模板列表*/
  336. $archivesLogic = new \app\admin\logic\ArchivesLogic;
  337. $templateList = $archivesLogic->getTemplateList($this->nid);
  338. $this->assign('templateList', $templateList);
  339. /*--end*/
  340. /*默认模板文件*/
  341. $tempview = 'view_'.$this->nid.'.'.config('template.view_suffix');
  342. !empty($arctypeInfo['tempview']) && $tempview = $arctypeInfo['tempview'];
  343. $this->assign('tempview', $tempview);
  344. /*--end*/
  345. // 商城配置
  346. $shopConfig = getUsersConfigData('shop');
  347. $assign_data['shopConfig'] = $shopConfig;
  348. // 商品规格
  349. if (isset($shopConfig['shop_open_spec']) && 1 == $shopConfig['shop_open_spec']) {
  350. // 预设值名称
  351. $assign_data['preset_value'] = Db::name('product_spec_preset')->where('lang',$this->admin_lang)->field('preset_id,preset_mark_id,preset_name')->group('preset_mark_id')->order('preset_mark_id desc')->select();
  352. }
  353. // URL模式
  354. $tpcache = config('tpcache');
  355. $assign_data['seo_pseudo'] = !empty($tpcache['seo_pseudo']) ? $tpcache['seo_pseudo'] : 1;
  356. $this->assign($assign_data);
  357. return $this->fetch();
  358. }
  359. /**
  360. * 编辑
  361. */
  362. public function edit()
  363. {
  364. if (IS_POST) {
  365. $post = input('post.');
  366. $typeid = input('post.typeid/d', 0);
  367. $content = input('post.addonFieldExt.content', '', null);
  368. // 根据标题自动提取相关的关键字
  369. $seo_keywords = $post['seo_keywords'];
  370. if (!empty($seo_keywords)) {
  371. $seo_keywords = str_replace(',', ',', $seo_keywords);
  372. } else {
  373. // $seo_keywords = get_split_word($post['title'], $content);
  374. }
  375. // 自动获取内容第一张图片作为封面图
  376. $is_remote = !empty($post['is_remote']) ? $post['is_remote'] : 0;
  377. $litpic = '';
  378. if ($is_remote == 1) {
  379. $litpic = $post['litpic_remote'];
  380. } else {
  381. $litpic = $post['litpic_local'];
  382. }
  383. if (empty($litpic)) {
  384. $litpic = get_html_first_imgurl($content);
  385. }
  386. $post['litpic'] = $litpic;
  387. /*是否有封面图*/
  388. if (empty($post['litpic'])) {
  389. $is_litpic = 0; // 无封面图
  390. } else {
  391. $is_litpic = !empty($post['is_litpic']) ? $post['is_litpic'] : 0; // 有封面图
  392. }
  393. // SEO描述
  394. $seo_description = '';
  395. if (empty($post['seo_description']) && !empty($content)) {
  396. $seo_description = @msubstr(checkStrHtml($content), 0, config('global.arc_seo_description_length'), false);
  397. } else {
  398. $seo_description = $post['seo_description'];
  399. }
  400. // --外部链接
  401. $jumplinks = '';
  402. $is_jump = isset($post['is_jump']) ? $post['is_jump'] : 0;
  403. if (intval($is_jump) > 0) {
  404. $jumplinks = $post['jumplinks'];
  405. }
  406. // 模板文件,如果文档模板名与栏目指定的一致,默认就为空。让它跟随栏目的指定而变
  407. if ($post['type_tempview'] == $post['tempview']) {
  408. unset($post['type_tempview']);
  409. unset($post['tempview']);
  410. }
  411. // 产品类型
  412. if (!empty($post['prom_type'])) {
  413. if ($post['prom_type_vir'] == 2) {
  414. $post['netdisk_url'] = trim($post['netdisk_url']);
  415. if (empty($post['netdisk_url'])) {
  416. $this->error("网盘地址不能为空!");
  417. }
  418. $post['prom_type'] = 2;
  419. } else if ($post['prom_type_vir'] == 3) {
  420. $post['text_content'] = trim($post['text_content']);
  421. if (empty($post['text_content'])) {
  422. $this->error("虚拟文本内容不能为空!");
  423. }
  424. $post['prom_type'] = 3;
  425. }
  426. }
  427. //处理自定义文件名,仅由字母数字下划线和短横杆组成,大写强制转换为小写
  428. if (!empty($post['htmlfilename'])) {
  429. $post['htmlfilename'] = preg_replace("/[^a-zA-Z0-9_-]+/", "", $post['htmlfilename']);
  430. $post['htmlfilename'] = strtolower($post['htmlfilename']);
  431. //判断是否存在相同的自定义文件名
  432. $filenameCount = Db::name('archives')->where([
  433. 'aid' => ['NEQ', $post['aid']],
  434. 'htmlfilename' => $post['htmlfilename'],
  435. ])->count();
  436. if (!empty($filenameCount)) {
  437. $this->error("自定义文件名已存在,请重新设置!");
  438. }
  439. }
  440. // 同步栏目切换模型之后的文档模型
  441. $channel = Db::name('arctype')->where(['id'=>$typeid])->getField('current_channel');
  442. // --存储数据
  443. $newData = array(
  444. 'typeid'=> $typeid,
  445. 'channel' => $channel,
  446. 'is_b' => empty($post['is_b']) ? 0 : $post['is_b'],
  447. 'is_head' => empty($post['is_head']) ? 0 : $post['is_head'],
  448. 'is_special' => empty($post['is_special']) ? 0 : $post['is_special'],
  449. 'is_recom' => empty($post['is_recom']) ? 0 : $post['is_recom'],
  450. 'is_jump' => $is_jump,
  451. 'is_litpic' => $is_litpic,
  452. 'jumplinks' => $jumplinks,
  453. 'seo_keywords' => $seo_keywords,
  454. 'seo_description' => $seo_description,
  455. 'stock_show' => empty($post['stock_show']) ? 0 : $post['stock_show'],
  456. 'add_time' => strtotime($post['add_time']),
  457. 'update_time' => getTime(),
  458. );
  459. $data = array_merge($post, $newData);
  460. $r = Db::name('archives')->where([
  461. 'aid' => $data['aid'],
  462. 'lang' => $this->admin_lang,
  463. ])->update($data);
  464. if ($r) {
  465. // ---------后置操作
  466. model('Product')->afterSave($data['aid'], $data, 'edit');
  467. // 更新规格名称数据
  468. // model('ProductSpecData')->ProducSpecNameEditSave($data);
  469. //虚拟商品保存
  470. if (!empty($post['prom_type']) && in_array($post['prom_type'], [2,3])) {
  471. model('ProductNetdisk')->saveProductNetdisk($data['aid'], $data);
  472. }
  473. // 更新规格值及金额数据
  474. model('ProductSpecValue')->ProducSpecValueEditSave($data);
  475. // ---------end
  476. adminLog('编辑产品:'.$data['title']);
  477. // 生成静态页面代码
  478. $successData = [
  479. 'aid' => $data['aid'],
  480. 'tid' => $typeid,
  481. ];
  482. $this->success("操作成功!", null, $successData);
  483. exit;
  484. }
  485. $this->error("操作失败!");
  486. exit;
  487. }
  488. $assign_data = array();
  489. $id = input('id/d');
  490. $info = model('Product')->getInfo($id);
  491. // 获取规格数据信息
  492. // 包含:SpecSelectName、HtmlTable、spec_mark_id_arr、preset_value
  493. $assign_data = model('ProductSpecData')->GetProductSpecData($id);
  494. if (empty($info)) {
  495. $this->error('数据不存在,请联系管理员!');
  496. exit;
  497. }
  498. /*兼容采集没有归属栏目的文档*/
  499. if (empty($info['channel'])) {
  500. $channelRow = Db::name('channeltype')->field('id as channel')
  501. ->where('id',$this->channeltype)
  502. ->find();
  503. $info = array_merge($info, $channelRow);
  504. }
  505. /*--end*/
  506. $typeid = $info['typeid'];
  507. // 栏目信息
  508. $arctypeInfo = Db::name('arctype')->find($typeid);
  509. $info['channel'] = $arctypeInfo['current_channel'];
  510. if (is_http_url($info['litpic'])) {
  511. $info['is_remote'] = 1;
  512. $info['litpic_remote'] = handle_subdir_pic($info['litpic']);
  513. } else {
  514. $info['is_remote'] = 0;
  515. $info['litpic_local'] = handle_subdir_pic($info['litpic']);
  516. }
  517. // SEO描述
  518. if (!empty($info['seo_description'])) {
  519. $info['seo_description'] = @msubstr(checkStrHtml($info['seo_description']), 0, config('global.arc_seo_description_length'), false);
  520. }
  521. $assign_data['field'] = $info;
  522. // 产品相册
  523. $proimg_list = model('ProductImg')->getProImg($id);
  524. foreach ($proimg_list as $key => $val) {
  525. $proimg_list[$key]['image_url'] = handle_subdir_pic($val['image_url']); // 支持子目录
  526. }
  527. $assign_data['proimg_list'] = $proimg_list;
  528. /*允许发布文档列表的栏目,文档所在模型以栏目所在模型为主,兼容切换模型之后的数据编辑*/
  529. $arctype_html = allow_release_arctype($typeid, array($info['channel']));
  530. $assign_data['arctype_html'] = $arctype_html;
  531. /*--end*/
  532. /*自定义字段*/
  533. $addonFieldExtList = model('Field')->getChannelFieldList($info['channel'], 0, $id, $info);
  534. $channelfieldBindRow = Db::name('channelfield_bind')->where([
  535. 'typeid' => ['IN', [0,$typeid]],
  536. ])->column('field_id');
  537. if (!empty($channelfieldBindRow)) {
  538. foreach ($addonFieldExtList as $key => $val) {
  539. if (!in_array($val['id'], $channelfieldBindRow)) {
  540. unset($addonFieldExtList[$key]);
  541. }
  542. }
  543. }
  544. $assign_data['addonFieldExtList'] = $addonFieldExtList;
  545. $assign_data['aid'] = $id;
  546. /*--end*/
  547. /*可控制的主表字段列表*/
  548. $assign_data['ifcontrolRow'] = Db::name('channelfield')->field('id,name')->where([
  549. 'channel_id' => $this->channeltype,
  550. 'ifmain' => 1,
  551. 'ifeditable' => 1,
  552. 'ifcontrol' => 0,
  553. 'status' => 1,
  554. ])->getAllWithIndex('name');
  555. /*虚拟商品内容读取*/
  556. $assign_data['netdisk'] = Db::name("product_netdisk")->where('aid', $id)->find();
  557. /*end*/
  558. // 阅读权限
  559. $arcrank_list = get_arcrank_list();
  560. $assign_data['arcrank_list'] = $arcrank_list;
  561. /*产品参数*/
  562. $assign_data['canshu'] = $this->ajax_get_attr_input($typeid, $id);
  563. /*--end*/
  564. /*模板列表*/
  565. $archivesLogic = new \app\admin\logic\ArchivesLogic;
  566. $templateList = $archivesLogic->getTemplateList($this->nid);
  567. $this->assign('templateList', $templateList);
  568. /*--end*/
  569. /*默认模板文件*/
  570. $tempview = $info['tempview'];
  571. empty($tempview) && $tempview = $arctypeInfo['tempview'];
  572. $this->assign('tempview', $tempview);
  573. /*--end*/
  574. // 商城配置
  575. $shopConfig = getUsersConfigData('shop');
  576. $assign_data['shopConfig'] = $shopConfig;
  577. // 处理产品价格属性
  578. $IsSame = '';
  579. if (empty($shopConfig['shop_type']) || 1 == $shopConfig['shop_type']) {
  580. if ($shopConfig['shop_type'] == $assign_data['field']['prom_type']) {
  581. $IsSame = '0'; // 相同
  582. }elseif ($shopConfig['shop_type']==1 && in_array($assign_data['field']['prom_type'], [2,3])) {
  583. $IsSame = '0'; // 相同
  584. }else{
  585. $IsSame = '1'; // 不相同
  586. }
  587. }
  588. $assign_data['IsSame'] = $IsSame;
  589. // URL模式
  590. $tpcache = config('tpcache');
  591. $assign_data['seo_pseudo'] = !empty($tpcache['seo_pseudo']) ? $tpcache['seo_pseudo'] : 1;
  592. $this->assign($assign_data);
  593. return $this->fetch();
  594. }
  595. /**
  596. * 删除
  597. */
  598. public function del()
  599. {
  600. if (IS_POST) {
  601. $archivesLogic = new \app\admin\logic\ArchivesLogic;
  602. $archivesLogic->del();
  603. }
  604. }
  605. /**
  606. * 删除商品相册图
  607. */
  608. public function del_proimg()
  609. {
  610. if (IS_POST) {
  611. $filename= input('filename/s');
  612. $filename= str_replace('../','',$filename);
  613. $filename= trim($filename,'.');
  614. if(eyPreventShell($filename) && !empty($filename)){
  615. $filename_new = trim($filename,'/');
  616. $filetype = preg_replace('/^(.*)\.(\w+)$/i', '$2', $filename);
  617. $phpfile = strtolower(strstr($filename,'.php')); //排除PHP文件
  618. $size = getimagesize($filename_new);
  619. $fileInfo = explode('/',$size['mime']);
  620. if((file_exists($filename_new) && $fileInfo[0] != 'image') || $phpfile || !in_array($filetype, explode(',', config('global.image_ext')))){
  621. exit;
  622. }
  623. if (!empty($filename)) {
  624. M('product_img')->where("image_url = '$filename'")->delete();
  625. }
  626. }
  627. }
  628. }
  629. /**
  630. * 产品参数
  631. */
  632. public function attribute_index()
  633. {
  634. $assign_data = array();
  635. $condition = array();
  636. // 获取到所有GET参数
  637. $get = input('get.');
  638. $typeid = input('typeid/d', 0);
  639. // 应用搜索条件
  640. foreach (['keywords','typeid'] as $key) {
  641. if (isset($get[$key]) && $get[$key] !== '') {
  642. if ($key == 'keywords') {
  643. $condition['a.attr_name'] = array('LIKE', "%{$get[$key]}%");
  644. } else if ($key == 'typeid') {
  645. $typeids = model('Arctype')->getHasChildren($get[$key]);
  646. $condition['a.typeid'] = array('IN', array_keys($typeids));
  647. } else {
  648. $condition['a.'.$key] = array('eq', $get[$key]);
  649. }
  650. }
  651. }
  652. $condition['a.is_del'] = 0;
  653. // 多语言
  654. $condition['a.lang'] = $this->admin_lang;
  655. /**
  656. * 数据查询,搜索出主键ID的值
  657. */
  658. $count = DB::name('product_attribute')->alias('a')->where($condition)->count();// 查询满足要求的总记录数
  659. $Page = new Page($count, config('paginate.list_rows'));// 实例化分页类 传入总记录数和每页显示的记录数
  660. $list = DB::name('product_attribute')
  661. ->field("a.attr_id")
  662. ->alias('a')
  663. ->where($condition)
  664. ->order('a.sort_order asc, a.attr_id asc')
  665. ->limit($Page->firstRow.','.$Page->listRows)
  666. ->getAllWithIndex('attr_id');
  667. /**
  668. * 完善数据集信息
  669. * 在数据量大的情况下,经过优化的搜索逻辑,先搜索出主键ID,再通过ID将其他信息补充完整;
  670. */
  671. if ($list) {
  672. $attr_ids = array_keys($list);
  673. $fields = "b.*, a.*";
  674. $row = DB::name('product_attribute')
  675. ->field($fields)
  676. ->alias('a')
  677. ->join('__ARCTYPE__ b', 'a.typeid = b.id', 'LEFT')
  678. ->where('a.attr_id', 'in', $attr_ids)
  679. ->getAllWithIndex('attr_id');
  680. /*获取多语言关联绑定的值*/
  681. $row = model('LanguageAttr')->getBindValue($row, 'product_attribute', $this->main_lang); // 多语言
  682. /*--end*/
  683. foreach ($row as $key => $val) {
  684. $val['fieldname'] = 'attr_'.$val['attr_id'];
  685. $row[$key] = $val;
  686. }
  687. foreach ($list as $key => $val) {
  688. $list[$key] = $row[$val['attr_id']];
  689. }
  690. }
  691. $show = $Page->show(); // 分页显示输出
  692. $assign_data['page'] = $show; // 赋值分页输出
  693. $assign_data['list'] = $list; // 赋值数据集
  694. $assign_data['pager'] = $Page; // 赋值分页对象
  695. /*获取当前模型栏目*/
  696. $selected = $typeid;
  697. $arctypeLogic = new ArctypeLogic();
  698. $map = array(
  699. 'channeltype' => $this->channeltype,
  700. 'is_del' => 0,
  701. );
  702. $arctype_max_level = intval(config('global.arctype_max_level'));
  703. $select_html = $arctypeLogic->arctype_list(0, $selected, true, $arctype_max_level, $map);
  704. $this->assign('select_html',$select_html);
  705. /*--end*/
  706. // 栏目ID
  707. $assign_data['typeid'] = $typeid; // 栏目ID
  708. /*当前栏目信息*/
  709. $arctype_info = array();
  710. if ($typeid > 0) {
  711. $arctype_info = M('arctype')->field('typename')->find($typeid);
  712. }
  713. $assign_data['arctype_info'] = $arctype_info;
  714. /*--end*/
  715. /*选项卡*/
  716. $tab = input('param.tab/d', 3);
  717. $assign_data['tab'] = $tab;
  718. /*--end*/
  719. $assign_data['attrInputTypeArr'] = $this->attrInputTypeArr; // 表单类型
  720. $this->assign($assign_data);
  721. return $this->fetch();
  722. }
  723. /**
  724. * 新增产品参数
  725. */
  726. public function attribute_add()
  727. {
  728. //防止php超时
  729. function_exists('set_time_limit') && set_time_limit(0);
  730. if(IS_AJAX && IS_POST)//ajax提交验证
  731. {
  732. $model = model('ProductAttribute');
  733. $attr_values = str_replace('_', '', input('attr_values')); // 替换特殊字符
  734. $attr_values = str_replace('@', '', $attr_values); // 替换特殊字符
  735. $attr_values = trim($attr_values);
  736. $post_data = input('post.');
  737. $post_data['attr_values'] = $attr_values;
  738. $savedata = array(
  739. 'attr_name' => $post_data['attr_name'],
  740. 'typeid' => $post_data['typeid'],
  741. 'attr_input_type' => isset($post_data['attr_input_type']) ? $post_data['attr_input_type'] : '',
  742. 'attr_values' => isset($post_data['attr_values']) ? $post_data['attr_values'] : '',
  743. 'sort_order' => $post_data['sort_order'],
  744. 'lang' => $this->admin_lang,
  745. 'add_time' => getTime(),
  746. 'update_time' => getTime(),
  747. );
  748. // 数据验证
  749. $validate = \think\Loader::validate('ProductAttribute');
  750. if(!$validate->batch()->check($savedata))
  751. {
  752. $error = $validate->getError();
  753. $error_msg = array_values($error);
  754. $return_arr = array(
  755. 'status' => -1,
  756. 'msg' => $error_msg[0],
  757. 'data' => $error,
  758. );
  759. respose($return_arr);
  760. } else {
  761. $model->data($savedata,true); // 收集数据
  762. $model->save(); // 写入数据到数据库
  763. $insertId = $model->getLastInsID();
  764. /*同步产品属性ID到多语言的模板变量里*/
  765. $this->syn_add_language_attribute($insertId);
  766. /*--end*/
  767. $return_arr = array(
  768. 'status' => 1,
  769. 'msg' => '操作成功',
  770. 'data' => array('url'=>url('Product/attribute_index', array('typeid'=>$post_data['typeid']))),
  771. );
  772. adminLog('新增产品参数:'.$savedata['attr_name']);
  773. respose($return_arr);
  774. }
  775. }
  776. $typeid = input('param.typeid/d', 0);
  777. $assign_data = array();
  778. /*允许发布文档列表的栏目*/
  779. $arctype_html = allow_release_arctype($typeid, array($this->channeltype));
  780. $assign_data['arctype_html'] = $arctype_html;
  781. /*--end*/
  782. $this->assign($assign_data);
  783. return $this->fetch();
  784. }
  785. /**
  786. * 编辑产品参数
  787. */
  788. public function attribute_edit()
  789. {
  790. if(IS_AJAX && IS_POST)//ajax提交验证
  791. {
  792. $model = model('ProductAttribute');
  793. $attr_values = str_replace('_', '', input('attr_values')); // 替换特殊字符
  794. $attr_values = str_replace('@', '', $attr_values); // 替换特殊字符
  795. $attr_values = trim($attr_values);
  796. $post_data = input('post.');
  797. $post_data['attr_values'] = $attr_values;
  798. $savedata = array(
  799. 'attr_id' => $post_data['attr_id'],
  800. 'attr_name' => $post_data['attr_name'],
  801. 'typeid' => $post_data['typeid'],
  802. 'attr_input_type' => isset($post_data['attr_input_type']) ? $post_data['attr_input_type'] : '',
  803. 'attr_values' => isset($post_data['attr_values']) ? $post_data['attr_values'] : '',
  804. 'sort_order' => $post_data['sort_order'],
  805. 'update_time' => getTime(),
  806. );
  807. // 数据验证
  808. $validate = \think\Loader::validate('ProductAttribute');
  809. if(!$validate->batch()->check($savedata))
  810. {
  811. $error = $validate->getError();
  812. $error_msg = array_values($error);
  813. $return_arr = array(
  814. 'status' => -1,
  815. 'msg' => $error_msg[0],
  816. 'data' => $error,
  817. );
  818. respose($return_arr);
  819. } else {
  820. $model->data($savedata,true); // 收集数据
  821. $model->isUpdate(true, [
  822. 'attr_id' => $post_data['attr_id'],
  823. 'lang' => $this->admin_lang,
  824. ])->save(); // 写入数据到数据库
  825. $return_arr = array(
  826. 'status' => 1,
  827. 'msg' => '操作成功',
  828. 'data' => array('url'=>url('Product/attribute_index', array('typeid'=>$post_data['typeid']))),
  829. );
  830. adminLog('编辑产品参数:'.$savedata['attr_name']);
  831. respose($return_arr);
  832. }
  833. }
  834. $assign_data = array();
  835. $id = input('id/d');
  836. /*获取多语言关联绑定的值*/
  837. $new_id = model('LanguageAttr')->getBindValue($id, 'product_attribute'); // 多语言
  838. !empty($new_id) && $id = $new_id;
  839. /*--end*/
  840. $info = M('ProductAttribute')->where([
  841. 'attr_id' => $id,
  842. 'lang' => $this->admin_lang,
  843. ])->find();
  844. if (empty($info)) {
  845. $this->error('数据不存在,请联系管理员!');
  846. exit;
  847. }
  848. $assign_data['field'] = $info;
  849. /*允许发布文档列表的栏目*/
  850. $arctype_html = allow_release_arctype($info['typeid'], array($this->channeltype));
  851. $assign_data['arctype_html'] = $arctype_html;
  852. /*--end*/
  853. $this->assign($assign_data);
  854. return $this->fetch();
  855. }
  856. /**
  857. * 删除产品参数
  858. */
  859. public function attribute_del()
  860. {
  861. $id_arr = input('del_id/a');
  862. $id_arr = eyIntval($id_arr);
  863. if(!empty($id_arr)){
  864. /*多语言*/
  865. if (is_language()) {
  866. $attr_name_arr = [];
  867. foreach ($id_arr as $key => $val) {
  868. $attr_name_arr[] = 'attr_'.$val;
  869. }
  870. $new_id_arr = Db::name('language_attr')->where([
  871. 'attr_name' => ['IN', $attr_name_arr],
  872. 'attr_group' => 'product_attribute',
  873. ])->column('attr_value');
  874. !empty($new_id_arr) && $id_arr = $new_id_arr;
  875. }
  876. /*--end*/
  877. $r = M('ProductAttribute')->where([
  878. 'attr_id' => ['IN', $id_arr],
  879. ])->update([
  880. 'is_del' => 1,
  881. 'update_time' => getTime(),
  882. ]);
  883. if($r){
  884. adminLog('删除产品参数-id:'.implode(',', $id_arr));
  885. $this->success('删除成功');
  886. }else{
  887. $this->error('删除失败');
  888. }
  889. }else{
  890. $this->error('参数有误');
  891. }
  892. }
  893. /**
  894. * 动态获取产品参数输入框 根据不同的数据返回不同的输入框类型
  895. */
  896. public function ajax_get_attr_input($typeid = '', $aid = '')
  897. {
  898. $productLogic = new ProductLogic();
  899. $str = $productLogic->getAttrInput($aid, $typeid);
  900. if (empty($str)) {
  901. $str = '<div style="font-size: 12px;text-align: center;">提示:该主栏目还没有参数值,若有需要请点击【<a href="'.url('Product/attribute_index', array('typeid'=>$typeid)).'">产品参数</a>】进行更多操作。</div>';
  902. }
  903. if (IS_AJAX) {
  904. exit($str);
  905. } else {
  906. return $str;
  907. }
  908. }
  909. /**
  910. * 同步新增产品属性ID到多语言的模板变量里
  911. */
  912. private function syn_add_language_attribute($attr_id)
  913. {
  914. /*单语言情况下不执行多语言代码*/
  915. if (!is_language()) {
  916. return true;
  917. }
  918. /*--end*/
  919. $attr_group = 'product_attribute';
  920. $admin_lang = $this->admin_lang;
  921. $main_lang = $this->main_lang;
  922. $languageRow = Db::name('language')->field('mark')->order('id asc')->select();
  923. if (!empty($languageRow) && $admin_lang == $main_lang) { // 当前语言是主体语言,即语言列表最早新增的语言
  924. $result = Db::name('product_attribute')->find($attr_id);
  925. $attr_name = 'attr_'.$attr_id;
  926. $r = Db::name('language_attribute')->save([
  927. 'attr_title' => $result['attr_name'],
  928. 'attr_name' => $attr_name,
  929. 'attr_group' => $attr_group,
  930. 'add_time' => getTime(),
  931. 'update_time' => getTime(),
  932. ]);
  933. if (false !== $r) {
  934. $data = [];
  935. foreach ($languageRow as $key => $val) {
  936. /*同步新产品属性到其他语言产品属性列表*/
  937. if ($val['mark'] != $admin_lang) {
  938. $addsaveData = $result;
  939. $addsaveData['lang'] = $val['mark'];
  940. $newTypeid = Db::name('language_attr')->where([
  941. 'attr_name' => 'tid'.$result['typeid'],
  942. 'attr_group' => 'arctype',
  943. 'lang' => $val['mark'],
  944. ])->getField('attr_value');
  945. $addsaveData['typeid'] = $newTypeid;
  946. unset($addsaveData['attr_id']);
  947. $attr_id = Db::name('product_attribute')->insertGetId($addsaveData);
  948. }
  949. /*--end*/
  950. /*所有语言绑定在主语言的ID容器里*/
  951. $data[] = [
  952. 'attr_name' => $attr_name,
  953. 'attr_value' => $attr_id,
  954. 'lang' => $val['mark'],
  955. 'attr_group' => $attr_group,
  956. 'add_time' => getTime(),
  957. 'update_time' => getTime(),
  958. ];
  959. /*--end*/
  960. }
  961. if (!empty($data)) {
  962. model('LanguageAttr')->saveAll($data);
  963. }
  964. }
  965. }
  966. }
  967. }