商品和规格关联完成
This commit is contained in:
parent
e65f914663
commit
345cad0956
@ -3,9 +3,13 @@ package com.ruoyi.winery.component;
|
||||
import cn.binarywang.wx.miniapp.api.WxMaService;
|
||||
import cn.binarywang.wx.miniapp.bean.WxMaJscode2SessionResult;
|
||||
import cn.binarywang.wx.miniapp.bean.WxMaPhoneNumberInfo;
|
||||
import cn.hutool.core.util.IdUtil;
|
||||
import cn.hutool.core.util.StrUtil;
|
||||
import cn.hutool.json.JSONObject;
|
||||
import com.github.binarywang.wxpay.service.WxPayService;
|
||||
import com.github.binarywang.wxpay.util.SignUtils;
|
||||
import com.ruoyi.common.core.redis.RedisCache;
|
||||
import com.ruoyi.winery.config.wx.WxMiniProperties;
|
||||
import com.ruoyi.winery.domain.winery.WineryMauser;
|
||||
import com.ruoyi.winery.service.IWineryMauserService;
|
||||
|
||||
@ -14,6 +18,8 @@ import me.chanjar.weixin.common.error.WxErrorException;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.stereotype.Component;
|
||||
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
import java.util.concurrent.TimeUnit;
|
||||
|
||||
|
||||
@ -36,6 +42,13 @@ public class MiniComponent {
|
||||
private RedisCache redisCache;
|
||||
|
||||
|
||||
@Autowired
|
||||
private WxMiniProperties wxMiniProperties;
|
||||
|
||||
@Autowired
|
||||
private WxPayService wxPayService;
|
||||
|
||||
|
||||
public WxMaJscode2SessionResult login(String code) throws WxErrorException {
|
||||
|
||||
WxMaJscode2SessionResult sessionInfo = wxMaService.getUserService().getSessionInfo(code);
|
||||
@ -88,4 +101,27 @@ public class MiniComponent {
|
||||
return mobile.getPhoneNumber();
|
||||
}
|
||||
|
||||
public JSONObject getRealAuthJson(String openid) {
|
||||
|
||||
|
||||
JSONObject json = new JSONObject();
|
||||
json.set("api_version", "1.0");
|
||||
json.set("mch_id", wxMiniProperties.getMchId());
|
||||
json.set("appid", wxMiniProperties.getAppId());
|
||||
json.set("scope", "pay_identity");
|
||||
json.set("response_type", "code");
|
||||
// json.set("openid", "okT7b4rOqy7FkJ_DxuBhyRPo0sGA");
|
||||
json.set("openid", openid);
|
||||
json.set("sign_type", "HMAC-SHA256");
|
||||
json.set("nonce_str", IdUtil.fastSimpleUUID());
|
||||
|
||||
Map<String, String> params = json.toBean(HashMap.class);
|
||||
|
||||
|
||||
json.set("sign", SignUtils.createSign(params, "HMAC-SHA256", wxMiniProperties.getMchKey(), (String[]) null));
|
||||
|
||||
|
||||
return json;
|
||||
}
|
||||
|
||||
}
|
||||
|
@ -0,0 +1,133 @@
|
||||
package com.ruoyi.winery.controller.goods;
|
||||
|
||||
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
|
||||
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
|
||||
|
||||
import java.util.List;
|
||||
import java.util.Arrays;
|
||||
|
||||
import com.ruoyi.common.utils.StringUtils;
|
||||
import lombok.RequiredArgsConstructor;
|
||||
import org.springframework.security.access.prepost.PreAuthorize;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.security.authentication.UsernamePasswordAuthenticationToken;
|
||||
import org.springframework.web.bind.annotation.GetMapping;
|
||||
import org.springframework.web.bind.annotation.PostMapping;
|
||||
import org.springframework.web.bind.annotation.PutMapping;
|
||||
import org.springframework.web.bind.annotation.DeleteMapping;
|
||||
import org.springframework.web.bind.annotation.PathVariable;
|
||||
import org.springframework.web.bind.annotation.RequestBody;
|
||||
import org.springframework.web.bind.annotation.RequestMapping;
|
||||
import org.springframework.web.bind.annotation.RestController;
|
||||
import com.ruoyi.common.annotation.Log;
|
||||
import com.ruoyi.common.core.controller.BaseController;
|
||||
import com.ruoyi.common.core.domain.AjaxResult;
|
||||
import com.ruoyi.common.enums.BusinessType;
|
||||
import com.ruoyi.winery.domain.goods.GoodsMain;
|
||||
import com.ruoyi.winery.service.IGoodsMainService;
|
||||
import com.ruoyi.common.utils.poi.ExcelUtil;
|
||||
import com.ruoyi.common.core.page.TableDataInfo;
|
||||
|
||||
/**
|
||||
* 商品信息Controller
|
||||
*
|
||||
* @author ruoyi
|
||||
* @date 2020-12-28
|
||||
*/
|
||||
@RequiredArgsConstructor(onConstructor_ = @Autowired)
|
||||
@RestController
|
||||
@RequestMapping("/goods/goods_main")
|
||||
public class GoodsMainController extends BaseController {
|
||||
|
||||
private final IGoodsMainService iWineryGoodsService;
|
||||
|
||||
/**
|
||||
* 查询商品信息列表
|
||||
*/
|
||||
@PreAuthorize("@ss.hasPermi('goods:goods_main:list')")
|
||||
@GetMapping("/list")
|
||||
public TableDataInfo list(UsernamePasswordAuthenticationToken token, GoodsMain goodsMain) {
|
||||
startPage();
|
||||
LambdaQueryWrapper<GoodsMain> lqw = Wrappers.lambdaQuery(goodsMain);
|
||||
|
||||
|
||||
lqw.eq(GoodsMain::getDeptId, getDeptId(token));
|
||||
|
||||
if (StringUtils.isNotBlank(goodsMain.getGoodsName())) {
|
||||
lqw.like(GoodsMain::getGoodsName, goodsMain.getGoodsName());
|
||||
}
|
||||
if (StringUtils.isNotBlank(goodsMain.getGoodsAlias())) {
|
||||
lqw.eq(GoodsMain::getGoodsAlias, goodsMain.getGoodsAlias());
|
||||
}
|
||||
if (StringUtils.isNotBlank(goodsMain.getGoodsType())) {
|
||||
lqw.eq(GoodsMain::getGoodsType, goodsMain.getGoodsType());
|
||||
}
|
||||
if (StringUtils.isNotBlank(goodsMain.getGoodsSpec())) {
|
||||
lqw.eq(GoodsMain::getGoodsSpec, goodsMain.getGoodsSpec());
|
||||
}
|
||||
if (StringUtils.isNotBlank(goodsMain.getGoodsDesc())) {
|
||||
lqw.eq(GoodsMain::getGoodsDesc, goodsMain.getGoodsDesc());
|
||||
}
|
||||
if (StringUtils.isNotBlank(goodsMain.getGoodsFaceImg())) {
|
||||
lqw.eq(GoodsMain::getGoodsFaceImg, goodsMain.getGoodsFaceImg());
|
||||
}
|
||||
if (StringUtils.isNotBlank(goodsMain.getGoodsImg())) {
|
||||
lqw.eq(GoodsMain::getGoodsImg, goodsMain.getGoodsImg());
|
||||
}
|
||||
List<GoodsMain> list = iWineryGoodsService.list(lqw);
|
||||
return getDataTable(list);
|
||||
}
|
||||
|
||||
/**
|
||||
* 导出商品信息列表
|
||||
*/
|
||||
@PreAuthorize("@ss.hasPermi('goods:goods_main:export')")
|
||||
@Log(title = "商品信息", businessType = BusinessType.EXPORT)
|
||||
@GetMapping("/export")
|
||||
public AjaxResult export(GoodsMain goodsMain) {
|
||||
LambdaQueryWrapper<GoodsMain> lqw = new LambdaQueryWrapper<GoodsMain>(goodsMain);
|
||||
List<GoodsMain> list = iWineryGoodsService.list(lqw);
|
||||
ExcelUtil<GoodsMain> util = new ExcelUtil<GoodsMain>(GoodsMain.class);
|
||||
return util.exportExcel(list, "winery_goods");
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取商品信息详细信息
|
||||
*/
|
||||
@PreAuthorize("@ss.hasPermi('goods:goods_main:query')")
|
||||
@GetMapping(value = "/{id}")
|
||||
public AjaxResult getInfo(@PathVariable("id") String id) {
|
||||
return AjaxResult.success(iWineryGoodsService.getById(id));
|
||||
}
|
||||
|
||||
/**
|
||||
* 新增商品信息
|
||||
*/
|
||||
@PreAuthorize("@ss.hasPermi('goods:goods_main:add')")
|
||||
@Log(title = "商品信息", businessType = BusinessType.INSERT)
|
||||
@PostMapping
|
||||
public AjaxResult add(UsernamePasswordAuthenticationToken token, @RequestBody GoodsMain goodsMain) {
|
||||
goodsMain.setDeptId(getDeptId(token));
|
||||
return toAjax(iWineryGoodsService.save(goodsMain) ? 1 : 0);
|
||||
}
|
||||
|
||||
/**
|
||||
* 修改商品信息
|
||||
*/
|
||||
@PreAuthorize("@ss.hasPermi('goods:goods_main:edit')")
|
||||
@Log(title = "商品信息", businessType = BusinessType.UPDATE)
|
||||
@PutMapping
|
||||
public AjaxResult edit(@RequestBody GoodsMain goodsMain) {
|
||||
return toAjax(iWineryGoodsService.updateById(goodsMain) ? 1 : 0);
|
||||
}
|
||||
|
||||
/**
|
||||
* 删除商品信息
|
||||
*/
|
||||
@PreAuthorize("@ss.hasPermi('goods:goods_main:remove')")
|
||||
@Log(title = "商品信息", businessType = BusinessType.DELETE)
|
||||
@DeleteMapping("/{ids}")
|
||||
public AjaxResult remove(@PathVariable Long[] ids) {
|
||||
return toAjax(iWineryGoodsService.removeByIds(Arrays.asList(ids)) ? 1 : 0);
|
||||
}
|
||||
}
|
@ -0,0 +1,127 @@
|
||||
package com.ruoyi.winery.controller.goods;
|
||||
|
||||
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
|
||||
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
|
||||
|
||||
import java.util.List;
|
||||
import java.util.Arrays;
|
||||
|
||||
import com.ruoyi.common.utils.StringUtils;
|
||||
import com.ruoyi.winery.domain.goods.GoodsSpec;
|
||||
import lombok.RequiredArgsConstructor;
|
||||
import org.springframework.security.access.prepost.PreAuthorize;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.security.authentication.UsernamePasswordAuthenticationToken;
|
||||
import org.springframework.web.bind.annotation.GetMapping;
|
||||
import org.springframework.web.bind.annotation.PostMapping;
|
||||
import org.springframework.web.bind.annotation.PutMapping;
|
||||
import org.springframework.web.bind.annotation.DeleteMapping;
|
||||
import org.springframework.web.bind.annotation.PathVariable;
|
||||
import org.springframework.web.bind.annotation.RequestBody;
|
||||
import org.springframework.web.bind.annotation.RequestMapping;
|
||||
import org.springframework.web.bind.annotation.RestController;
|
||||
import com.ruoyi.common.annotation.Log;
|
||||
import com.ruoyi.common.core.controller.BaseController;
|
||||
import com.ruoyi.common.core.domain.AjaxResult;
|
||||
import com.ruoyi.common.enums.BusinessType;
|
||||
import com.ruoyi.winery.service.IGoodsSpecService;
|
||||
import com.ruoyi.common.utils.poi.ExcelUtil;
|
||||
import com.ruoyi.common.core.page.TableDataInfo;
|
||||
|
||||
/**
|
||||
* 商品规格Controller
|
||||
*
|
||||
* @author ruoyi
|
||||
* @date 2020-12-28
|
||||
*/
|
||||
@RequiredArgsConstructor(onConstructor_ = @Autowired)
|
||||
@RestController
|
||||
@RequestMapping("/goods/goods_spec")
|
||||
public class GoodsSpecController extends BaseController {
|
||||
|
||||
private final IGoodsSpecService iWineryGoodsSpecService;
|
||||
|
||||
/**
|
||||
* 查询商品规格列表
|
||||
*/
|
||||
@PreAuthorize("@ss.hasPermi('goods:goods_spec:list')")
|
||||
@GetMapping("/list")
|
||||
public TableDataInfo list(UsernamePasswordAuthenticationToken token, GoodsSpec goodsSpec) {
|
||||
startPage();
|
||||
|
||||
LambdaQueryWrapper<GoodsSpec> lqw = Wrappers.lambdaQuery(goodsSpec);
|
||||
|
||||
lqw.eq(GoodsSpec::getDeptId, getDeptId(token));
|
||||
|
||||
if (StringUtils.isNotBlank(goodsSpec.getSpecName())) {
|
||||
lqw.like(GoodsSpec::getSpecName, goodsSpec.getSpecName());
|
||||
}
|
||||
if (StringUtils.isNotBlank(goodsSpec.getSpecDesc())) {
|
||||
lqw.eq(GoodsSpec::getSpecDesc, goodsSpec.getSpecDesc());
|
||||
}
|
||||
if (StringUtils.isNotBlank(goodsSpec.getSpecImg())) {
|
||||
lqw.eq(GoodsSpec::getSpecImg, goodsSpec.getSpecImg());
|
||||
}
|
||||
if (goodsSpec.getSpecPrice() != null) {
|
||||
lqw.eq(GoodsSpec::getSpecPrice, goodsSpec.getSpecPrice());
|
||||
}
|
||||
if (goodsSpec.getDetailSpec() != null) {
|
||||
lqw.eq(GoodsSpec::getDetailSpec, goodsSpec.getDetailSpec());
|
||||
}
|
||||
List<GoodsSpec> list = iWineryGoodsSpecService.list(lqw);
|
||||
return getDataTable(list);
|
||||
}
|
||||
|
||||
/**
|
||||
* 导出商品规格列表
|
||||
*/
|
||||
@PreAuthorize("@ss.hasPermi('goods:goods_spec:export')")
|
||||
@Log(title = "商品规格", businessType = BusinessType.EXPORT)
|
||||
@GetMapping("/export")
|
||||
public AjaxResult export(GoodsSpec goodsSpec) {
|
||||
LambdaQueryWrapper<GoodsSpec> lqw = new LambdaQueryWrapper<GoodsSpec>(goodsSpec);
|
||||
List<GoodsSpec> list = iWineryGoodsSpecService.list(lqw);
|
||||
ExcelUtil<GoodsSpec> util = new ExcelUtil<GoodsSpec>(GoodsSpec.class);
|
||||
return util.exportExcel(list, "spec");
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取商品规格详细信息
|
||||
*/
|
||||
@PreAuthorize("@ss.hasPermi('goods:goods_spec:query')")
|
||||
@GetMapping(value = "/{id}")
|
||||
public AjaxResult getInfo(@PathVariable("id") String id) {
|
||||
return AjaxResult.success(iWineryGoodsSpecService.getById(id));
|
||||
}
|
||||
|
||||
/**
|
||||
* 新增商品规格
|
||||
*/
|
||||
@PreAuthorize("@ss.hasPermi('goods:goods_spec:add')")
|
||||
@Log(title = "商品规格", businessType = BusinessType.INSERT)
|
||||
@PostMapping
|
||||
public AjaxResult add(UsernamePasswordAuthenticationToken token, @RequestBody GoodsSpec goodsSpec) {
|
||||
goodsSpec.setDeptId(getDeptId(token));
|
||||
return toAjax(iWineryGoodsSpecService.save(goodsSpec) ? 1 : 0);
|
||||
}
|
||||
|
||||
/**
|
||||
* 修改商品规格
|
||||
*/
|
||||
@PreAuthorize("@ss.hasPermi('goods:goods_spec:edit')")
|
||||
@Log(title = "商品规格", businessType = BusinessType.UPDATE)
|
||||
@PutMapping
|
||||
public AjaxResult edit(@RequestBody GoodsSpec goodsSpec) {
|
||||
return toAjax(iWineryGoodsSpecService.updateById(goodsSpec) ? 1 : 0);
|
||||
}
|
||||
|
||||
/**
|
||||
* 删除商品规格
|
||||
*/
|
||||
@PreAuthorize("@ss.hasPermi('goods:goods_spec:remove')")
|
||||
@Log(title = "商品规格", businessType = BusinessType.DELETE)
|
||||
@DeleteMapping("/{ids}")
|
||||
public AjaxResult remove(@PathVariable Long[] ids) {
|
||||
return toAjax(iWineryGoodsSpecService.removeByIds(Arrays.asList(ids)) ? 1 : 0);
|
||||
}
|
||||
}
|
@ -102,6 +102,14 @@ public class MiniController {
|
||||
|
||||
}
|
||||
|
||||
@GetMapping("/getRealAuthJson")
|
||||
AjaxResult getRealAuthJson(@RequestParam String openid) {
|
||||
|
||||
|
||||
return AjaxResult.success(miniComponent.getRealAuthJson(openid));
|
||||
|
||||
}
|
||||
|
||||
private WineryCompanyRecord parseRecordWineryModel(JSONObject json) {
|
||||
|
||||
WineryCompanyRecord record = new WineryCompanyRecord();
|
||||
|
@ -1,131 +0,0 @@
|
||||
package com.ruoyi.winery.controller.winery;
|
||||
|
||||
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
|
||||
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
|
||||
|
||||
import java.util.List;
|
||||
import java.util.Arrays;
|
||||
|
||||
import com.ruoyi.common.utils.StringUtils;
|
||||
import lombok.RequiredArgsConstructor;
|
||||
import org.springframework.security.access.prepost.PreAuthorize;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.web.bind.annotation.GetMapping;
|
||||
import org.springframework.web.bind.annotation.PostMapping;
|
||||
import org.springframework.web.bind.annotation.PutMapping;
|
||||
import org.springframework.web.bind.annotation.DeleteMapping;
|
||||
import org.springframework.web.bind.annotation.PathVariable;
|
||||
import org.springframework.web.bind.annotation.RequestBody;
|
||||
import org.springframework.web.bind.annotation.RequestMapping;
|
||||
import org.springframework.web.bind.annotation.RestController;
|
||||
import com.ruoyi.common.annotation.Log;
|
||||
import com.ruoyi.common.core.controller.BaseController;
|
||||
import com.ruoyi.common.core.domain.AjaxResult;
|
||||
import com.ruoyi.common.enums.BusinessType;
|
||||
import com.ruoyi.winery.domain.winery.WineryGoods;
|
||||
import com.ruoyi.winery.service.IWineryGoodsService;
|
||||
import com.ruoyi.common.utils.poi.ExcelUtil;
|
||||
import com.ruoyi.common.core.page.TableDataInfo;
|
||||
|
||||
/**
|
||||
* 商品信息Controller
|
||||
*
|
||||
* @author ruoyi
|
||||
* @date 2020-12-28
|
||||
*/
|
||||
@RequiredArgsConstructor(onConstructor_ = @Autowired)
|
||||
@RestController
|
||||
@RequestMapping("/winery/winery_goods" )
|
||||
public class WineryGoodsController extends BaseController {
|
||||
|
||||
private final IWineryGoodsService iWineryGoodsService;
|
||||
|
||||
/**
|
||||
* 查询商品信息列表
|
||||
*/
|
||||
@PreAuthorize("@ss.hasPermi('winery:winery_goods:list')")
|
||||
@GetMapping("/list")
|
||||
public TableDataInfo list(WineryGoods wineryGoods)
|
||||
{
|
||||
startPage();
|
||||
LambdaQueryWrapper<WineryGoods> lqw = Wrappers.lambdaQuery(wineryGoods);
|
||||
if (wineryGoods.getDeptId() != null){
|
||||
lqw.eq(WineryGoods::getDeptId ,wineryGoods.getDeptId());
|
||||
}
|
||||
if (StringUtils.isNotBlank(wineryGoods.getGoodsName())){
|
||||
lqw.like(WineryGoods::getGoodsName ,wineryGoods.getGoodsName());
|
||||
}
|
||||
if (StringUtils.isNotBlank(wineryGoods.getGoodsAlias())){
|
||||
lqw.eq(WineryGoods::getGoodsAlias ,wineryGoods.getGoodsAlias());
|
||||
}
|
||||
if (StringUtils.isNotBlank(wineryGoods.getGoodsType())){
|
||||
lqw.eq(WineryGoods::getGoodsType ,wineryGoods.getGoodsType());
|
||||
}
|
||||
if (StringUtils.isNotBlank(wineryGoods.getGoodsSpec())){
|
||||
lqw.eq(WineryGoods::getGoodsSpec ,wineryGoods.getGoodsSpec());
|
||||
}
|
||||
if (StringUtils.isNotBlank(wineryGoods.getGoodsDesc())){
|
||||
lqw.eq(WineryGoods::getGoodsDesc ,wineryGoods.getGoodsDesc());
|
||||
}
|
||||
if (StringUtils.isNotBlank(wineryGoods.getGoodsFaceImg())){
|
||||
lqw.eq(WineryGoods::getGoodsFaceImg ,wineryGoods.getGoodsFaceImg());
|
||||
}
|
||||
if (StringUtils.isNotBlank(wineryGoods.getGoodsImg())){
|
||||
lqw.eq(WineryGoods::getGoodsImg ,wineryGoods.getGoodsImg());
|
||||
}
|
||||
List<WineryGoods> list = iWineryGoodsService.list(lqw);
|
||||
return getDataTable(list);
|
||||
}
|
||||
|
||||
/**
|
||||
* 导出商品信息列表
|
||||
*/
|
||||
@PreAuthorize("@ss.hasPermi('winery:winery_goods:export')" )
|
||||
@Log(title = "商品信息" , businessType = BusinessType.EXPORT)
|
||||
@GetMapping("/export" )
|
||||
public AjaxResult export(WineryGoods wineryGoods) {
|
||||
LambdaQueryWrapper<WineryGoods> lqw = new LambdaQueryWrapper<WineryGoods>(wineryGoods);
|
||||
List<WineryGoods> list = iWineryGoodsService.list(lqw);
|
||||
ExcelUtil<WineryGoods> util = new ExcelUtil<WineryGoods>(WineryGoods. class);
|
||||
return util.exportExcel(list, "winery_goods" );
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取商品信息详细信息
|
||||
*/
|
||||
@PreAuthorize("@ss.hasPermi('winery:winery_goods:query')" )
|
||||
@GetMapping(value = "/{id}" )
|
||||
public AjaxResult getInfo(@PathVariable("id" ) Long id) {
|
||||
return AjaxResult.success(iWineryGoodsService.getById(id));
|
||||
}
|
||||
|
||||
/**
|
||||
* 新增商品信息
|
||||
*/
|
||||
@PreAuthorize("@ss.hasPermi('winery:winery_goods:add')" )
|
||||
@Log(title = "商品信息" , businessType = BusinessType.INSERT)
|
||||
@PostMapping
|
||||
public AjaxResult add(@RequestBody WineryGoods wineryGoods) {
|
||||
return toAjax(iWineryGoodsService.save(wineryGoods) ? 1 : 0);
|
||||
}
|
||||
|
||||
/**
|
||||
* 修改商品信息
|
||||
*/
|
||||
@PreAuthorize("@ss.hasPermi('winery:winery_goods:edit')" )
|
||||
@Log(title = "商品信息" , businessType = BusinessType.UPDATE)
|
||||
@PutMapping
|
||||
public AjaxResult edit(@RequestBody WineryGoods wineryGoods) {
|
||||
return toAjax(iWineryGoodsService.updateById(wineryGoods) ? 1 : 0);
|
||||
}
|
||||
|
||||
/**
|
||||
* 删除商品信息
|
||||
*/
|
||||
@PreAuthorize("@ss.hasPermi('winery:winery_goods:remove')" )
|
||||
@Log(title = "商品信息" , businessType = BusinessType.DELETE)
|
||||
@DeleteMapping("/{ids}" )
|
||||
public AjaxResult remove(@PathVariable Long[] ids) {
|
||||
return toAjax(iWineryGoodsService.removeByIds(Arrays.asList(ids)) ? 1 : 0);
|
||||
}
|
||||
}
|
@ -1,125 +0,0 @@
|
||||
package com.ruoyi.winery.controller.winery;
|
||||
|
||||
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
|
||||
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
|
||||
|
||||
import java.util.List;
|
||||
import java.util.Arrays;
|
||||
|
||||
import com.ruoyi.common.utils.StringUtils;
|
||||
import lombok.RequiredArgsConstructor;
|
||||
import org.springframework.security.access.prepost.PreAuthorize;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.web.bind.annotation.GetMapping;
|
||||
import org.springframework.web.bind.annotation.PostMapping;
|
||||
import org.springframework.web.bind.annotation.PutMapping;
|
||||
import org.springframework.web.bind.annotation.DeleteMapping;
|
||||
import org.springframework.web.bind.annotation.PathVariable;
|
||||
import org.springframework.web.bind.annotation.RequestBody;
|
||||
import org.springframework.web.bind.annotation.RequestMapping;
|
||||
import org.springframework.web.bind.annotation.RestController;
|
||||
import com.ruoyi.common.annotation.Log;
|
||||
import com.ruoyi.common.core.controller.BaseController;
|
||||
import com.ruoyi.common.core.domain.AjaxResult;
|
||||
import com.ruoyi.common.enums.BusinessType;
|
||||
import com.ruoyi.winery.domain.winery.WineryGoodsSpec;
|
||||
import com.ruoyi.winery.service.IWineryGoodsSpecService;
|
||||
import com.ruoyi.common.utils.poi.ExcelUtil;
|
||||
import com.ruoyi.common.core.page.TableDataInfo;
|
||||
|
||||
/**
|
||||
* 商品规格Controller
|
||||
*
|
||||
* @author ruoyi
|
||||
* @date 2020-12-28
|
||||
*/
|
||||
@RequiredArgsConstructor(onConstructor_ = @Autowired)
|
||||
@RestController
|
||||
@RequestMapping("/winery/spec" )
|
||||
public class WineryGoodsSpecController extends BaseController {
|
||||
|
||||
private final IWineryGoodsSpecService iWineryGoodsSpecService;
|
||||
|
||||
/**
|
||||
* 查询商品规格列表
|
||||
*/
|
||||
@PreAuthorize("@ss.hasPermi('winery:spec:list')")
|
||||
@GetMapping("/list")
|
||||
public TableDataInfo list(WineryGoodsSpec wineryGoodsSpec)
|
||||
{
|
||||
startPage();
|
||||
LambdaQueryWrapper<WineryGoodsSpec> lqw = Wrappers.lambdaQuery(wineryGoodsSpec);
|
||||
if (wineryGoodsSpec.getDeptId() != null){
|
||||
lqw.eq(WineryGoodsSpec::getDeptId ,wineryGoodsSpec.getDeptId());
|
||||
}
|
||||
if (StringUtils.isNotBlank(wineryGoodsSpec.getSpecName())){
|
||||
lqw.like(WineryGoodsSpec::getSpecName ,wineryGoodsSpec.getSpecName());
|
||||
}
|
||||
if (StringUtils.isNotBlank(wineryGoodsSpec.getSpecDesc())){
|
||||
lqw.eq(WineryGoodsSpec::getSpecDesc ,wineryGoodsSpec.getSpecDesc());
|
||||
}
|
||||
if (StringUtils.isNotBlank(wineryGoodsSpec.getSpecImg())){
|
||||
lqw.eq(WineryGoodsSpec::getSpecImg ,wineryGoodsSpec.getSpecImg());
|
||||
}
|
||||
if (wineryGoodsSpec.getSpecPrice() != null){
|
||||
lqw.eq(WineryGoodsSpec::getSpecPrice ,wineryGoodsSpec.getSpecPrice());
|
||||
}
|
||||
if (wineryGoodsSpec.getDetailSpec() != null){
|
||||
lqw.eq(WineryGoodsSpec::getDetailSpec ,wineryGoodsSpec.getDetailSpec());
|
||||
}
|
||||
List<WineryGoodsSpec> list = iWineryGoodsSpecService.list(lqw);
|
||||
return getDataTable(list);
|
||||
}
|
||||
|
||||
/**
|
||||
* 导出商品规格列表
|
||||
*/
|
||||
@PreAuthorize("@ss.hasPermi('winery:spec:export')" )
|
||||
@Log(title = "商品规格" , businessType = BusinessType.EXPORT)
|
||||
@GetMapping("/export" )
|
||||
public AjaxResult export(WineryGoodsSpec wineryGoodsSpec) {
|
||||
LambdaQueryWrapper<WineryGoodsSpec> lqw = new LambdaQueryWrapper<WineryGoodsSpec>(wineryGoodsSpec);
|
||||
List<WineryGoodsSpec> list = iWineryGoodsSpecService.list(lqw);
|
||||
ExcelUtil<WineryGoodsSpec> util = new ExcelUtil<WineryGoodsSpec>(WineryGoodsSpec. class);
|
||||
return util.exportExcel(list, "spec" );
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取商品规格详细信息
|
||||
*/
|
||||
@PreAuthorize("@ss.hasPermi('winery:spec:query')" )
|
||||
@GetMapping(value = "/{id}" )
|
||||
public AjaxResult getInfo(@PathVariable("id" ) Long id) {
|
||||
return AjaxResult.success(iWineryGoodsSpecService.getById(id));
|
||||
}
|
||||
|
||||
/**
|
||||
* 新增商品规格
|
||||
*/
|
||||
@PreAuthorize("@ss.hasPermi('winery:spec:add')" )
|
||||
@Log(title = "商品规格" , businessType = BusinessType.INSERT)
|
||||
@PostMapping
|
||||
public AjaxResult add(@RequestBody WineryGoodsSpec wineryGoodsSpec) {
|
||||
return toAjax(iWineryGoodsSpecService.save(wineryGoodsSpec) ? 1 : 0);
|
||||
}
|
||||
|
||||
/**
|
||||
* 修改商品规格
|
||||
*/
|
||||
@PreAuthorize("@ss.hasPermi('winery:spec:edit')" )
|
||||
@Log(title = "商品规格" , businessType = BusinessType.UPDATE)
|
||||
@PutMapping
|
||||
public AjaxResult edit(@RequestBody WineryGoodsSpec wineryGoodsSpec) {
|
||||
return toAjax(iWineryGoodsSpecService.updateById(wineryGoodsSpec) ? 1 : 0);
|
||||
}
|
||||
|
||||
/**
|
||||
* 删除商品规格
|
||||
*/
|
||||
@PreAuthorize("@ss.hasPermi('winery:spec:remove')" )
|
||||
@Log(title = "商品规格" , businessType = BusinessType.DELETE)
|
||||
@DeleteMapping("/{ids}" )
|
||||
public AjaxResult remove(@PathVariable Long[] ids) {
|
||||
return toAjax(iWineryGoodsSpecService.removeByIds(Arrays.asList(ids)) ? 1 : 0);
|
||||
}
|
||||
}
|
@ -69,6 +69,5 @@ private static final long serialVersionUID=1L;
|
||||
private Integer newsType;
|
||||
|
||||
/** 状态 */
|
||||
@Excel(name = "状态")
|
||||
private Integer state;
|
||||
}
|
||||
|
@ -1,4 +1,4 @@
|
||||
package com.ruoyi.winery.domain.winery;
|
||||
package com.ruoyi.winery.domain.goods;
|
||||
|
||||
import com.fasterxml.jackson.annotation.JsonFormat;
|
||||
import lombok.Data;
|
||||
@ -26,8 +26,8 @@ import com.ruoyi.common.core.domain.BaseEntity;
|
||||
@EqualsAndHashCode
|
||||
@NoArgsConstructor
|
||||
@Accessors(chain = true)
|
||||
@TableName("winery_goods")
|
||||
public class WineryGoods implements Serializable {
|
||||
@TableName("goods_main")
|
||||
public class GoodsMain implements Serializable {
|
||||
|
||||
private static final long serialVersionUID=1L;
|
||||
|
||||
@ -83,4 +83,9 @@ private static final long serialVersionUID=1L;
|
||||
/** 备注 */
|
||||
@Excel(name = "备注")
|
||||
private String remark;
|
||||
|
||||
/**
|
||||
* 状态
|
||||
*/
|
||||
private Integer state;
|
||||
}
|
@ -1,4 +1,4 @@
|
||||
package com.ruoyi.winery.domain.winery;
|
||||
package com.ruoyi.winery.domain.goods;
|
||||
|
||||
import com.fasterxml.jackson.annotation.JsonFormat;
|
||||
import lombok.Data;
|
||||
@ -26,8 +26,8 @@ import com.ruoyi.common.core.domain.BaseEntity;
|
||||
@EqualsAndHashCode
|
||||
@NoArgsConstructor
|
||||
@Accessors(chain = true)
|
||||
@TableName("winery_goods_spec")
|
||||
public class WineryGoodsSpec implements Serializable {
|
||||
@TableName("goods_spec")
|
||||
public class GoodsSpec implements Serializable {
|
||||
|
||||
private static final long serialVersionUID=1L;
|
||||
|
||||
@ -66,7 +66,7 @@ private static final long serialVersionUID=1L;
|
||||
|
||||
/** 规格单价 */
|
||||
@Excel(name = "规格单价")
|
||||
private Long specPrice;
|
||||
private BigDecimal specPrice;
|
||||
|
||||
/** 规格详细 */
|
||||
@Excel(name = "规格详细")
|
@ -80,7 +80,7 @@ public class WineryOrders implements Serializable {
|
||||
* 商品基准单价
|
||||
*/
|
||||
@Excel(name = "商品基准单价")
|
||||
private Long goodsPrice;
|
||||
private BigDecimal goodsPrice;
|
||||
|
||||
/**
|
||||
* 商品数量
|
||||
|
@ -1,6 +1,6 @@
|
||||
package com.ruoyi.winery.mapper;
|
||||
|
||||
import com.ruoyi.winery.domain.winery.WineryGoods;
|
||||
import com.ruoyi.winery.domain.goods.GoodsMain;
|
||||
import com.baomidou.mybatisplus.core.mapper.BaseMapper;
|
||||
|
||||
/**
|
||||
@ -9,6 +9,6 @@ import com.baomidou.mybatisplus.core.mapper.BaseMapper;
|
||||
* @author ruoyi
|
||||
* @date 2020-12-28
|
||||
*/
|
||||
public interface WineryGoodsMapper extends BaseMapper<WineryGoods> {
|
||||
public interface GoodsMainMapper extends BaseMapper<GoodsMain> {
|
||||
|
||||
}
|
@ -1,6 +1,6 @@
|
||||
package com.ruoyi.winery.mapper;
|
||||
|
||||
import com.ruoyi.winery.domain.winery.WineryGoodsSpec;
|
||||
import com.ruoyi.winery.domain.goods.GoodsSpec;
|
||||
import com.baomidou.mybatisplus.core.mapper.BaseMapper;
|
||||
|
||||
/**
|
||||
@ -9,6 +9,6 @@ import com.baomidou.mybatisplus.core.mapper.BaseMapper;
|
||||
* @author ruoyi
|
||||
* @date 2020-12-28
|
||||
*/
|
||||
public interface WineryGoodsSpecMapper extends BaseMapper<WineryGoodsSpec> {
|
||||
public interface GoodsSpecMapper extends BaseMapper<GoodsSpec> {
|
||||
|
||||
}
|
@ -1,6 +1,6 @@
|
||||
package com.ruoyi.winery.service;
|
||||
|
||||
import com.ruoyi.winery.domain.winery.WineryGoods;
|
||||
import com.ruoyi.winery.domain.goods.GoodsMain;
|
||||
import com.baomidou.mybatisplus.extension.service.IService;
|
||||
|
||||
/**
|
||||
@ -9,6 +9,6 @@ import com.baomidou.mybatisplus.extension.service.IService;
|
||||
* @author ruoyi
|
||||
* @date 2020-12-28
|
||||
*/
|
||||
public interface IWineryGoodsService extends IService<WineryGoods> {
|
||||
public interface IGoodsMainService extends IService<GoodsMain> {
|
||||
|
||||
}
|
@ -1,6 +1,6 @@
|
||||
package com.ruoyi.winery.service;
|
||||
|
||||
import com.ruoyi.winery.domain.winery.WineryGoodsSpec;
|
||||
import com.ruoyi.winery.domain.goods.GoodsSpec;
|
||||
import com.baomidou.mybatisplus.extension.service.IService;
|
||||
|
||||
/**
|
||||
@ -9,6 +9,6 @@ import com.baomidou.mybatisplus.extension.service.IService;
|
||||
* @author ruoyi
|
||||
* @date 2020-12-28
|
||||
*/
|
||||
public interface IWineryGoodsSpecService extends IService<WineryGoodsSpec> {
|
||||
public interface IGoodsSpecService extends IService<GoodsSpec> {
|
||||
|
||||
}
|
@ -1,10 +1,10 @@
|
||||
package com.ruoyi.winery.service.impl;
|
||||
|
||||
import com.ruoyi.winery.mapper.GoodsMainMapper;
|
||||
import org.springframework.stereotype.Service;
|
||||
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
|
||||
import com.ruoyi.winery.mapper.WineryGoodsMapper;
|
||||
import com.ruoyi.winery.domain.winery.WineryGoods;
|
||||
import com.ruoyi.winery.service.IWineryGoodsService;
|
||||
import com.ruoyi.winery.domain.goods.GoodsMain;
|
||||
import com.ruoyi.winery.service.IGoodsMainService;
|
||||
|
||||
/**
|
||||
* 商品信息Service业务层处理
|
||||
@ -13,6 +13,6 @@ import com.ruoyi.winery.service.IWineryGoodsService;
|
||||
* @date 2020-12-28
|
||||
*/
|
||||
@Service
|
||||
public class WineryGoodsServiceImpl extends ServiceImpl<WineryGoodsMapper, WineryGoods> implements IWineryGoodsService {
|
||||
public class WineryGoodsServiceImpl extends ServiceImpl<GoodsMainMapper, GoodsMain> implements IGoodsMainService {
|
||||
|
||||
}
|
||||
|
@ -2,9 +2,9 @@ package com.ruoyi.winery.service.impl;
|
||||
|
||||
import org.springframework.stereotype.Service;
|
||||
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
|
||||
import com.ruoyi.winery.mapper.WineryGoodsSpecMapper;
|
||||
import com.ruoyi.winery.domain.winery.WineryGoodsSpec;
|
||||
import com.ruoyi.winery.service.IWineryGoodsSpecService;
|
||||
import com.ruoyi.winery.mapper.GoodsSpecMapper;
|
||||
import com.ruoyi.winery.domain.goods.GoodsSpec;
|
||||
import com.ruoyi.winery.service.IGoodsSpecService;
|
||||
|
||||
/**
|
||||
* 商品规格Service业务层处理
|
||||
@ -13,6 +13,6 @@ import com.ruoyi.winery.service.IWineryGoodsSpecService;
|
||||
* @date 2020-12-28
|
||||
*/
|
||||
@Service
|
||||
public class WineryGoodsSpecServiceImpl extends ServiceImpl<WineryGoodsSpecMapper, WineryGoodsSpec> implements IWineryGoodsSpecService {
|
||||
public class WineryGoodsSpecServiceImpl extends ServiceImpl<GoodsSpecMapper, GoodsSpec> implements IGoodsSpecService {
|
||||
|
||||
}
|
||||
|
@ -2,9 +2,9 @@
|
||||
<!DOCTYPE mapper
|
||||
PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
|
||||
"http://mybatis.org/dtd/mybatis-3-mapper.dtd">
|
||||
<mapper namespace="com.ruoyi.winery.mapper.WineryGoodsMapper">
|
||||
<mapper namespace="com.ruoyi.winery.mapper.GoodsMainMapper">
|
||||
|
||||
<resultMap type="WineryGoods" id="WineryGoodsResult">
|
||||
<resultMap type="GoodsMain" id="GoodsMainResult">
|
||||
<result property="id" column="id" />
|
||||
<result property="deptId" column="dept_id" />
|
||||
<result property="goodsName" column="goods_name" />
|
@ -2,9 +2,9 @@
|
||||
<!DOCTYPE mapper
|
||||
PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
|
||||
"http://mybatis.org/dtd/mybatis-3-mapper.dtd">
|
||||
<mapper namespace="com.ruoyi.winery.mapper.WineryGoodsSpecMapper">
|
||||
<mapper namespace="com.ruoyi.winery.mapper.GoodsSpecMapper">
|
||||
|
||||
<resultMap type="WineryGoodsSpec" id="WineryGoodsSpecResult">
|
||||
<resultMap type="GoodsSpec" id="GoodsSpecResult">
|
||||
<result property="id" column="id" />
|
||||
<result property="deptId" column="dept_id" />
|
||||
<result property="createBy" column="create_by" />
|
@ -42,9 +42,18 @@ public class CosUtils {
|
||||
@Autowired
|
||||
private CosProperties properties;
|
||||
|
||||
// 指定要上传到的存储桶
|
||||
/**
|
||||
* 正则异常字符
|
||||
*/
|
||||
String SPECIAL_CHARACTERS = "[`~! @#$%^&*()+=|{}':;',//[//]<>/?~!@#¥%……&*()_——+|{}【】‘;:”“’。,、?]";
|
||||
|
||||
/**
|
||||
* 表单提交文件
|
||||
*
|
||||
* @param type
|
||||
* @param file
|
||||
* @return
|
||||
*/
|
||||
public String upload(String type, MultipartFile file) {
|
||||
|
||||
|
||||
@ -69,10 +78,42 @@ public class CosUtils {
|
||||
|
||||
}
|
||||
|
||||
public void getFile(String fileName, HttpServletResponse response) {
|
||||
|
||||
/**
|
||||
* 上传文件
|
||||
*
|
||||
* @param type
|
||||
* @param fileKey
|
||||
* @param file
|
||||
* @return
|
||||
*/
|
||||
public String uploadFile(String type, String fileKey, File file) {
|
||||
|
||||
// 指定要上传到 COS 上对象键
|
||||
String key = ReUtil.replaceAll(StrUtil.trim(Optional.of(fileKey).orElse(StrUtil.EMPTY)), SPECIAL_CHARACTERS, StrUtil.EMPTY);
|
||||
// 生成 cos 客户端。
|
||||
COSClient cosClient = new COSClient(cosCredentials, clientConfig);
|
||||
try {
|
||||
PutObjectResult putObjectResult = cosClient.putObject(properties.getBucketName(), type + "/" + key, file);
|
||||
} catch (Exception e) {
|
||||
} finally {
|
||||
|
||||
cosClient.shutdown();
|
||||
}
|
||||
return type + "/" + key;
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* 根据文件key下载文件
|
||||
*
|
||||
* @param fileKey
|
||||
* @param response
|
||||
*/
|
||||
public void getFile(String fileKey, HttpServletResponse response) {
|
||||
|
||||
COSClient cosClient = new COSClient(cosCredentials, clientConfig);
|
||||
GetObjectRequest getObjectRequest = new GetObjectRequest(properties.getBucketName(), fileName);
|
||||
GetObjectRequest getObjectRequest = new GetObjectRequest(properties.getBucketName(), fileKey);
|
||||
// 限流使用的单位是bit/s, 这里设置下载带宽限制为 10MB/s
|
||||
getObjectRequest.setTrafficLimit(80 * 1024 * 1024);
|
||||
|
||||
@ -110,22 +151,4 @@ public class CosUtils {
|
||||
}
|
||||
|
||||
|
||||
public String uploadFile(String type, String filename, File file) {
|
||||
|
||||
|
||||
// 指定要上传到 COS 上对象键
|
||||
String key = ReUtil.replaceAll(StrUtil.trim(Optional.of(filename).orElse(StrUtil.EMPTY)), SPECIAL_CHARACTERS, StrUtil.EMPTY);
|
||||
// 生成 cos 客户端。
|
||||
COSClient cosClient = new COSClient(cosCredentials, clientConfig);
|
||||
try {
|
||||
PutObjectResult putObjectResult = cosClient.putObject(properties.getBucketName(), type + "/" + key, file);
|
||||
} catch (Exception e) {
|
||||
} finally {
|
||||
|
||||
cosClient.shutdown();
|
||||
}
|
||||
return type + "/" + key;
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
@ -3,7 +3,7 @@ import request from '@/utils/request'
|
||||
// 查询商品信息列表
|
||||
export function listWinery_goods(query) {
|
||||
return request({
|
||||
url: '/winery/winery_goods/list',
|
||||
url: '/goods/goods_main/list',
|
||||
method: 'get',
|
||||
params: query
|
||||
})
|
||||
@ -12,7 +12,7 @@ export function listWinery_goods(query) {
|
||||
// 查询商品信息详细
|
||||
export function getWinery_goods(id) {
|
||||
return request({
|
||||
url: '/winery/winery_goods/' + id,
|
||||
url: '/goods/goods_main/' + id,
|
||||
method: 'get'
|
||||
})
|
||||
}
|
||||
@ -20,7 +20,7 @@ export function getWinery_goods(id) {
|
||||
// 新增商品信息
|
||||
export function addWinery_goods(data) {
|
||||
return request({
|
||||
url: '/winery/winery_goods',
|
||||
url: '/goods/goods_main',
|
||||
method: 'post',
|
||||
data: data
|
||||
})
|
||||
@ -29,7 +29,7 @@ export function addWinery_goods(data) {
|
||||
// 修改商品信息
|
||||
export function updateWinery_goods(data) {
|
||||
return request({
|
||||
url: '/winery/winery_goods',
|
||||
url: '/goods/goods_main',
|
||||
method: 'put',
|
||||
data: data
|
||||
})
|
||||
@ -38,7 +38,7 @@ export function updateWinery_goods(data) {
|
||||
// 删除商品信息
|
||||
export function delWinery_goods(id) {
|
||||
return request({
|
||||
url: '/winery/winery_goods/' + id,
|
||||
url: '/goods/goods_main/' + id,
|
||||
method: 'delete'
|
||||
})
|
||||
}
|
||||
@ -46,8 +46,8 @@ export function delWinery_goods(id) {
|
||||
// 导出商品信息
|
||||
export function exportWinery_goods(query) {
|
||||
return request({
|
||||
url: '/winery/winery_goods/export',
|
||||
url: '/goods/goods_main/export',
|
||||
method: 'get',
|
||||
params: query
|
||||
})
|
||||
}
|
||||
}
|
@ -3,7 +3,7 @@ import request from '@/utils/request'
|
||||
// 查询商品规格列表
|
||||
export function listSpec(query) {
|
||||
return request({
|
||||
url: '/winery/spec/list',
|
||||
url: '/goods/goods_spec/list',
|
||||
method: 'get',
|
||||
params: query
|
||||
})
|
||||
@ -12,7 +12,7 @@ export function listSpec(query) {
|
||||
// 查询商品规格详细
|
||||
export function getSpec(id) {
|
||||
return request({
|
||||
url: '/winery/spec/' + id,
|
||||
url: '/goods/goods_spec/' + id,
|
||||
method: 'get'
|
||||
})
|
||||
}
|
||||
@ -20,7 +20,7 @@ export function getSpec(id) {
|
||||
// 新增商品规格
|
||||
export function addSpec(data) {
|
||||
return request({
|
||||
url: '/winery/spec',
|
||||
url: '/goods/goods_spec',
|
||||
method: 'post',
|
||||
data: data
|
||||
})
|
||||
@ -29,7 +29,7 @@ export function addSpec(data) {
|
||||
// 修改商品规格
|
||||
export function updateSpec(data) {
|
||||
return request({
|
||||
url: '/winery/spec',
|
||||
url: '/goods/goods_spec',
|
||||
method: 'put',
|
||||
data: data
|
||||
})
|
||||
@ -38,7 +38,7 @@ export function updateSpec(data) {
|
||||
// 删除商品规格
|
||||
export function delSpec(id) {
|
||||
return request({
|
||||
url: '/winery/spec/' + id,
|
||||
url: '/goods/goods_spec/' + id,
|
||||
method: 'delete'
|
||||
})
|
||||
}
|
||||
@ -46,8 +46,8 @@ export function delSpec(id) {
|
||||
// 导出商品规格
|
||||
export function exportSpec(query) {
|
||||
return request({
|
||||
url: '/winery/spec/export',
|
||||
url: '/goods/goods_spec/export',
|
||||
method: 'get',
|
||||
params: query
|
||||
})
|
||||
}
|
||||
}
|
@ -19,8 +19,6 @@
|
||||
@keyup.enter.native="handleQuery"
|
||||
/>
|
||||
</el-form-item>
|
||||
|
||||
|
||||
<el-form-item label="商品类型" prop="goodsType">
|
||||
<el-select v-model="queryParams.goodsType" placeholder="请选择商品类型" clearable size="small">
|
||||
<el-option label="请选择字典生成" value=""/>
|
||||
@ -48,7 +46,7 @@
|
||||
icon="el-icon-plus"
|
||||
size="mini"
|
||||
@click="handleAdd"
|
||||
v-hasPermi="['winery:winery_goods:add']"
|
||||
v-hasPermi="['goods:goods_main:add']"
|
||||
>新增
|
||||
</el-button>
|
||||
</el-col>
|
||||
@ -59,7 +57,7 @@
|
||||
size="mini"
|
||||
:disabled="single"
|
||||
@click="handleUpdate"
|
||||
v-hasPermi="['winery:winery_goods:edit']"
|
||||
v-hasPermi="['goods:goods_main:edit']"
|
||||
>修改
|
||||
</el-button>
|
||||
</el-col>
|
||||
@ -70,7 +68,7 @@
|
||||
size="mini"
|
||||
:disabled="multiple"
|
||||
@click="handleDelete"
|
||||
v-hasPermi="['winery:winery_goods:remove']"
|
||||
v-hasPermi="['goods:goods_main:remove']"
|
||||
>删除
|
||||
</el-button>
|
||||
</el-col>
|
||||
@ -80,27 +78,34 @@
|
||||
icon="el-icon-download"
|
||||
size="mini"
|
||||
@click="handleExport"
|
||||
v-hasPermi="['winery:winery_goods:export']"
|
||||
v-hasPermi="['goods:goods_main:export']"
|
||||
>导出
|
||||
</el-button>
|
||||
</el-col>
|
||||
<right-toolbar :showSearch.sync="showSearch" @queryTable="getList"></right-toolbar>
|
||||
</el-row>
|
||||
|
||||
<el-table v-loading="loading" :data="winery_goodsList" @selection-change="handleSelectionChange">
|
||||
<el-table v-loading="loading" :data="goodsList" @selection-change="handleSelectionChange">
|
||||
<el-table-column type="selection" width="55" align="center"/>
|
||||
<el-table-column label="商品ID" align="center" prop="id" v-if="false"/>
|
||||
<el-table-column label="商品名称" align="center" prop="goodsName"/>
|
||||
<el-table-column label="商品简称" align="center" prop="goodsAlias"/>
|
||||
<el-table-column label="商品类型" align="center" prop="goodsType"/>
|
||||
<!-- <el-table-column label="关联规格" align="center" prop="goodsSpec"/>-->
|
||||
<el-table-column label="商品说明" align="center" prop="goodsDesc"/>
|
||||
<!-- <el-table-column label="关联规格" align="center" prop="goodsSpec"/>-->
|
||||
<!-- <el-table-column label="商品说明" align="center" prop="goodsDesc"/>-->
|
||||
<el-table-column label="商品封面" align="center" prop="goodsFaceImg">
|
||||
<template slot-scope="scope">
|
||||
<el-image :src="scope.row.goodsFaceImg|getImageForKey" style="width: 60px; height: 60px" />
|
||||
<el-image :src="scope.row.goodsFaceImg|getImageForKey" style="width: 60px; height: 60px"/>
|
||||
</template>
|
||||
</el-table-column>
|
||||
<!-- <el-table-column label="商品图片" align="center" prop="goodsImg"/>-->
|
||||
<el-table-column label="状态" align="center" prop="state" :formatter="stateFormat" width="100px">
|
||||
<template slot-scope="scope">
|
||||
<el-tag :type="scope.row.state === 1 ? 'success' : 'danger'">
|
||||
{{scope.row.state | getStateName(stateOptions)}}
|
||||
</el-tag>
|
||||
</template>
|
||||
</el-table-column>
|
||||
<!-- <el-table-column label="商品图片" align="center" prop="goodsImg"/>-->
|
||||
<el-table-column label="备注" align="center" prop="remark"/>
|
||||
<el-table-column label="操作" align="center" class-name="small-padding fixed-width">
|
||||
<template slot-scope="scope">
|
||||
@ -109,7 +114,7 @@
|
||||
type="text"
|
||||
icon="el-icon-edit"
|
||||
@click="handleUpdate(scope.row)"
|
||||
v-hasPermi="['winery:winery_goods:edit']"
|
||||
v-hasPermi="['goods:goods_main:edit']"
|
||||
>修改
|
||||
</el-button>
|
||||
<el-button
|
||||
@ -117,7 +122,7 @@
|
||||
type="text"
|
||||
icon="el-icon-delete"
|
||||
@click="handleDelete(scope.row)"
|
||||
v-hasPermi="['winery:winery_goods:remove']"
|
||||
v-hasPermi="['goods:goods_main:remove']"
|
||||
>删除
|
||||
</el-button>
|
||||
</template>
|
||||
@ -133,7 +138,7 @@
|
||||
/>
|
||||
|
||||
<!-- 添加或修改商品信息对话框 -->
|
||||
<el-dialog :title="title" :visible.sync="open" width="500px" append-to-body>
|
||||
<el-dialog :title="title" :visible.sync="open" width="1000px" append-to-body>
|
||||
<el-form ref="form" :model="form" :rules="rules" label-width="80px">
|
||||
|
||||
<el-form-item label="商品名称" prop="goodsName">
|
||||
@ -142,27 +147,38 @@
|
||||
<el-form-item label="商品简称" prop="goodsAlias">
|
||||
<el-input v-model="form.goodsAlias" placeholder="请输入商品简称"/>
|
||||
</el-form-item>
|
||||
<el-form-item label="商品封面" prop="goodsFaceImg">
|
||||
<upload-image :value="form.goodsFaceImg" @input="inputGoodsFaceImg"/>
|
||||
<!-- <el-input v-model="form.goodsFaceImg" placeholder="请输入商品封面" />-->
|
||||
</el-form-item>
|
||||
<el-form-item label="商品图片" prop="goodsImg">
|
||||
<upload-image-multiple :value="form.goodsImg" @input="inputGoodsImg"/>
|
||||
<!-- <el-input v-model="form.goodsImg" placeholder="请输入商品图片"/>-->
|
||||
</el-form-item>
|
||||
<el-form-item label="状态" prop="state">
|
||||
|
||||
<el-radio-group v-model="form.state">
|
||||
<el-radio v-for="(dict, index) in stateOptions" :key="index" :label="parseInt(dict.dictValue)">{{dict.dictLabel}}</el-radio>
|
||||
</el-radio-group>
|
||||
</el-form-item>
|
||||
<el-form-item label="商品类型" prop="goodsType">
|
||||
<el-select v-model="form.goodsType" placeholder="请选择商品类型">
|
||||
<el-option label="请选择字典生成" value=""/>
|
||||
</el-select>
|
||||
</el-form-item>
|
||||
<el-form-item label="关联规格" prop="goodsSpec">
|
||||
<el-input v-model="form.goodsSpec" type="textarea" placeholder="请输入内容"/>
|
||||
<!-- <el-input v-model="form.goodsSpec" type="textarea" placeholder="请输入内容"/>-->
|
||||
<el-transfer v-model="selectedSpecData" :data="specData" filterable
|
||||
:titles="['商品列表','已关联商品']"
|
||||
:button-texts="['取消关联', '关联商品']"
|
||||
@change="handleChangeSpec"
|
||||
></el-transfer>
|
||||
</el-form-item>
|
||||
<el-form-item label="商品说明" prop="goodsDesc">
|
||||
<el-input v-model="form.goodsDesc" placeholder="请输入商品说明"/>
|
||||
<!-- <el-input v-model="form.goodsDesc" placeholder="请输入商品说明"/>-->
|
||||
<editor :value="form.goodsDesc" :height="400" :min-height="400" @on-change="onChangeGoodsDesc"/>
|
||||
</el-form-item>
|
||||
<el-form-item label="商品封面" prop="goodsFaceImg">
|
||||
|
||||
|
||||
<upload-image :value="form.goodsFaceImg" @input="inputGoodsFaceImg"/>
|
||||
<!-- <el-input v-model="form.goodsFaceImg" placeholder="请输入商品封面" />-->
|
||||
</el-form-item>
|
||||
<el-form-item label="商品图片" prop="goodsImg">
|
||||
<upload-image-multiple :value="form.goodsImg" @input="inputGoodsImg"/>
|
||||
<!-- <el-input v-model="form.goodsImg" placeholder="请输入商品图片"/>-->
|
||||
</el-form-item>
|
||||
<el-form-item label="备注" prop="remark">
|
||||
<el-input v-model="form.remark" type="textarea" placeholder="请输入内容"/>
|
||||
</el-form-item>
|
||||
@ -183,18 +199,22 @@ import {
|
||||
addWinery_goods,
|
||||
updateWinery_goods,
|
||||
exportWinery_goods
|
||||
} from "@/api/winery/winery_goods";
|
||||
} from "@/api/goods/goods_main";
|
||||
import UploadImage from '@/components/UploadImage/index'
|
||||
import UploadImageMultiple from '@/components/UploadImageMultiple/index'
|
||||
|
||||
import CommonMixin from "@/mixin/common";
|
||||
import Editor from '@/components/Editor/index';
|
||||
import {listSpec} from "@/api/goods/goods_spec";
|
||||
import {getDictName} from "@/utils/utils";
|
||||
|
||||
export default {
|
||||
name: "Winery_goods",
|
||||
mixins:[CommonMixin],
|
||||
name: "GoodsMain",
|
||||
mixins: [CommonMixin],
|
||||
components: {
|
||||
UploadImage,
|
||||
UploadImageMultiple,
|
||||
Editor
|
||||
},
|
||||
computed: {},
|
||||
data() {
|
||||
@ -212,11 +232,13 @@ export default {
|
||||
// 总条数
|
||||
total: 0,
|
||||
// 商品信息表格数据
|
||||
winery_goodsList: [],
|
||||
goodsList: [],
|
||||
// 弹出层标题
|
||||
title: "",
|
||||
// 是否显示弹出层
|
||||
open: false,
|
||||
// 状态字典
|
||||
stateOptions: [],
|
||||
// 查询参数
|
||||
queryParams: {
|
||||
pageNum: 1,
|
||||
@ -228,15 +250,30 @@ export default {
|
||||
goodsDesc: undefined,
|
||||
goodsFaceImg: undefined,
|
||||
goodsImg: undefined,
|
||||
state: undefined
|
||||
},
|
||||
// 表单参数
|
||||
form: {},
|
||||
// 表单校验
|
||||
rules: {}
|
||||
rules: {},
|
||||
|
||||
// 规格
|
||||
specData: [],
|
||||
// 已选规格
|
||||
selectedSpecData: []
|
||||
|
||||
};
|
||||
},
|
||||
filters: {
|
||||
getStateName(value, options) {
|
||||
return getDictName(value, options)
|
||||
}
|
||||
},
|
||||
created() {
|
||||
this.getList();
|
||||
this.getDicts("sys_release_status").then(response => {
|
||||
this.stateOptions = response.data;
|
||||
});
|
||||
},
|
||||
methods: {
|
||||
inputGoodsFaceImg(fileName) {
|
||||
@ -246,11 +283,15 @@ export default {
|
||||
inputGoodsImg(fileName) {
|
||||
this.form.goodsImg = fileName
|
||||
},
|
||||
// 状态字典翻译
|
||||
stateFormat(row, column) {
|
||||
return this.selectDictLabel(this.stateOptions, row.state);
|
||||
},
|
||||
/** 查询商品信息列表 */
|
||||
getList() {
|
||||
this.loading = true;
|
||||
listWinery_goods(this.queryParams).then(response => {
|
||||
this.winery_goodsList = response.rows;
|
||||
this.goodsList = response.rows;
|
||||
this.total = response.total;
|
||||
this.loading = false;
|
||||
});
|
||||
@ -309,6 +350,22 @@ export default {
|
||||
this.form = response.data;
|
||||
this.open = true;
|
||||
this.title = "修改商品信息";
|
||||
|
||||
listSpec({
|
||||
pageNum: 1,
|
||||
pageSize: 999
|
||||
}).then(r => {
|
||||
this.specData = []
|
||||
for (let i = 0; i < r.rows.length; i++) {
|
||||
this.specData.push({
|
||||
key: r.rows[i].id,
|
||||
label: r.rows[i].specName,
|
||||
// disabled: i % 4 === 0
|
||||
});
|
||||
}
|
||||
|
||||
this.selectedSpecData = this.form.goodsSpec.split(',')
|
||||
})
|
||||
});
|
||||
},
|
||||
/** 提交按钮 */
|
||||
@ -316,6 +373,7 @@ export default {
|
||||
this.$refs["form"].validate(valid => {
|
||||
if (valid) {
|
||||
if (this.form.id != null) {
|
||||
this.form.goodsSpec = this.selectedSpecData.join(',')
|
||||
updateWinery_goods(this.form).then(response => {
|
||||
this.msgSuccess("修改成功");
|
||||
this.open = false;
|
||||
@ -357,6 +415,21 @@ export default {
|
||||
}).then(response => {
|
||||
this.download(response.msg);
|
||||
})
|
||||
},
|
||||
/**
|
||||
* 商品详情
|
||||
* @param value
|
||||
*/
|
||||
onChangeGoodsDesc(value) {
|
||||
this.form.goodsDesc = value.html
|
||||
},
|
||||
|
||||
|
||||
/**
|
||||
* 规格关联穿梭框
|
||||
*/
|
||||
handleChangeSpec(value, direction, movedKeys) {
|
||||
console.log(value, direction, movedKeys);
|
||||
}
|
||||
}
|
||||
};
|
@ -1,15 +1,15 @@
|
||||
<template>
|
||||
<div class="app-container">
|
||||
<el-form :model="queryParams" ref="queryForm" :inline="true" v-show="showSearch" label-width="68px">
|
||||
<el-form-item label="部门ID" prop="deptId">
|
||||
<el-input
|
||||
v-model="queryParams.deptId"
|
||||
placeholder="请输入部门ID"
|
||||
clearable
|
||||
size="small"
|
||||
@keyup.enter.native="handleQuery"
|
||||
/>
|
||||
</el-form-item>
|
||||
<!-- <el-form-item label="部门ID" prop="deptId">-->
|
||||
<!-- <el-input-->
|
||||
<!-- v-model="queryParams.deptId"-->
|
||||
<!-- placeholder="请输入部门ID"-->
|
||||
<!-- clearable-->
|
||||
<!-- size="small"-->
|
||||
<!-- @keyup.enter.native="handleQuery"-->
|
||||
<!-- />-->
|
||||
<!-- </el-form-item>-->
|
||||
<el-form-item label="规格名称" prop="specName">
|
||||
<el-input
|
||||
v-model="queryParams.specName"
|
||||
@ -28,15 +28,15 @@
|
||||
@keyup.enter.native="handleQuery"
|
||||
/>
|
||||
</el-form-item>
|
||||
<el-form-item label="规格图片" prop="specImg">
|
||||
<el-input
|
||||
v-model="queryParams.specImg"
|
||||
placeholder="请输入规格图片"
|
||||
clearable
|
||||
size="small"
|
||||
@keyup.enter.native="handleQuery"
|
||||
/>
|
||||
</el-form-item>
|
||||
<!-- <el-form-item label="规格图片" prop="specImg">-->
|
||||
<!-- <el-input-->
|
||||
<!-- v-model="queryParams.specImg"-->
|
||||
<!-- placeholder="请输入规格图片"-->
|
||||
<!-- clearable-->
|
||||
<!-- size="small"-->
|
||||
<!-- @keyup.enter.native="handleQuery"-->
|
||||
<!-- />-->
|
||||
<!-- </el-form-item>-->
|
||||
<el-form-item label="规格单价" prop="specPrice">
|
||||
<el-input
|
||||
v-model="queryParams.specPrice"
|
||||
@ -46,15 +46,15 @@
|
||||
@keyup.enter.native="handleQuery"
|
||||
/>
|
||||
</el-form-item>
|
||||
<el-form-item label="规格详细" prop="detailSpec">
|
||||
<el-input
|
||||
v-model="queryParams.detailSpec"
|
||||
placeholder="请输入规格详细"
|
||||
clearable
|
||||
size="small"
|
||||
@keyup.enter.native="handleQuery"
|
||||
/>
|
||||
</el-form-item>
|
||||
<!-- <el-form-item label="规格详细" prop="detailSpec">-->
|
||||
<!-- <el-input-->
|
||||
<!-- v-model="queryParams.detailSpec"-->
|
||||
<!-- placeholder="请输入规格详细"-->
|
||||
<!-- clearable-->
|
||||
<!-- size="small"-->
|
||||
<!-- @keyup.enter.native="handleQuery"-->
|
||||
<!-- />-->
|
||||
<!-- </el-form-item>-->
|
||||
<el-form-item>
|
||||
<el-button type="cyan" icon="el-icon-search" size="mini" @click="handleQuery">搜索</el-button>
|
||||
<el-button icon="el-icon-refresh" size="mini" @click="resetQuery">重置</el-button>
|
||||
@ -68,7 +68,7 @@
|
||||
icon="el-icon-plus"
|
||||
size="mini"
|
||||
@click="handleAdd"
|
||||
v-hasPermi="['winery:spec:add']"
|
||||
v-hasPermi="['winery:goods_spec:add']"
|
||||
>新增</el-button>
|
||||
</el-col>
|
||||
<el-col :span="1.5">
|
||||
@ -78,7 +78,7 @@
|
||||
size="mini"
|
||||
:disabled="single"
|
||||
@click="handleUpdate"
|
||||
v-hasPermi="['winery:spec:edit']"
|
||||
v-hasPermi="['winery:goods_spec:edit']"
|
||||
>修改</el-button>
|
||||
</el-col>
|
||||
<el-col :span="1.5">
|
||||
@ -88,7 +88,7 @@
|
||||
size="mini"
|
||||
:disabled="multiple"
|
||||
@click="handleDelete"
|
||||
v-hasPermi="['winery:spec:remove']"
|
||||
v-hasPermi="['winery:goods_spec:remove']"
|
||||
>删除</el-button>
|
||||
</el-col>
|
||||
<el-col :span="1.5">
|
||||
@ -97,7 +97,7 @@
|
||||
icon="el-icon-download"
|
||||
size="mini"
|
||||
@click="handleExport"
|
||||
v-hasPermi="['winery:spec:export']"
|
||||
v-hasPermi="['winery:goods_spec:export']"
|
||||
>导出</el-button>
|
||||
</el-col>
|
||||
<right-toolbar :showSearch.sync="showSearch" @queryTable="getList"></right-toolbar>
|
||||
@ -106,12 +106,18 @@
|
||||
<el-table v-loading="loading" :data="specList" @selection-change="handleSelectionChange">
|
||||
<el-table-column type="selection" width="55" align="center" />
|
||||
<el-table-column label="规格ID" align="center" prop="id" v-if="false"/>
|
||||
<el-table-column label="部门ID" align="center" prop="deptId" />
|
||||
<!-- <el-table-column label="部门ID" align="center" prop="deptId" />-->
|
||||
<el-table-column label="规格名称" align="center" prop="specName" />
|
||||
<el-table-column label="规格图片" align="center" prop="specImg" >
|
||||
<template slot-scope="scope">
|
||||
<el-image :src="scope.row.specImg|getImageForKey" style="width: 60px; height: 60px"/>
|
||||
</template>
|
||||
</el-table-column>
|
||||
<el-table-column label="规格单价(元)" align="center" prop="specPrice" />
|
||||
<el-table-column label="规格说明" align="center" prop="specDesc" />
|
||||
<el-table-column label="规格图片" align="center" prop="specImg" />
|
||||
<el-table-column label="规格单价" align="center" prop="specPrice" />
|
||||
<el-table-column label="规格详细" align="center" prop="detailSpec" />
|
||||
|
||||
|
||||
<!-- <el-table-column label="规格详细" align="center" prop="detailSpec" />-->
|
||||
<el-table-column label="备注" align="center" prop="remark" />
|
||||
<el-table-column label="操作" align="center" class-name="small-padding fixed-width">
|
||||
<template slot-scope="scope">
|
||||
@ -120,19 +126,19 @@
|
||||
type="text"
|
||||
icon="el-icon-edit"
|
||||
@click="handleUpdate(scope.row)"
|
||||
v-hasPermi="['winery:spec:edit']"
|
||||
v-hasPermi="['winery:goods_spec:edit']"
|
||||
>修改</el-button>
|
||||
<el-button
|
||||
size="mini"
|
||||
type="text"
|
||||
icon="el-icon-delete"
|
||||
@click="handleDelete(scope.row)"
|
||||
v-hasPermi="['winery:spec:remove']"
|
||||
v-hasPermi="['winery:goods_spec:remove']"
|
||||
>删除</el-button>
|
||||
</template>
|
||||
</el-table-column>
|
||||
</el-table>
|
||||
|
||||
|
||||
<pagination
|
||||
v-show="total>0"
|
||||
:total="total"
|
||||
@ -143,10 +149,10 @@
|
||||
|
||||
<!-- 添加或修改商品规格对话框 -->
|
||||
<el-dialog :title="title" :visible.sync="open" width="500px" append-to-body>
|
||||
<el-form ref="form" :model="form" :rules="rules" label-width="80px">
|
||||
<el-form-item label="部门ID" prop="deptId">
|
||||
<el-input v-model="form.deptId" placeholder="请输入部门ID" />
|
||||
</el-form-item>
|
||||
<el-form ref="form" :model="form" :rules="rules" label-width="80px" >
|
||||
<!-- <el-form-item label="部门ID" prop="deptId">-->
|
||||
<!-- <el-input v-model="form.deptId" placeholder="请输入部门ID" />-->
|
||||
<!-- </el-form-item>-->
|
||||
<el-form-item label="规格名称" prop="specName">
|
||||
<el-input v-model="form.specName" placeholder="请输入规格名称" />
|
||||
</el-form-item>
|
||||
@ -154,10 +160,11 @@
|
||||
<el-input v-model="form.specDesc" placeholder="请输入规格说明" />
|
||||
</el-form-item>
|
||||
<el-form-item label="规格图片" prop="specImg">
|
||||
<el-input v-model="form.specImg" placeholder="请输入规格图片" />
|
||||
<!-- <el-input v-model="form.specImg" placeholder="请输入规格图片" />-->
|
||||
<uploadImage v-model="form.specImg"/>
|
||||
</el-form-item>
|
||||
<el-form-item label="规格单价" prop="specPrice">
|
||||
<el-input v-model="form.specPrice" placeholder="请输入规格单价" />
|
||||
<el-form-item label="规格单价(元)" prop="specPrice">
|
||||
<el-input v-model="form.specPrice" type="number" placeholder="请输入规格单价" />
|
||||
</el-form-item>
|
||||
<el-form-item label="规格详细" prop="detailSpec">
|
||||
<el-input v-model="form.detailSpec" placeholder="请输入规格详细" />
|
||||
@ -175,11 +182,15 @@
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import { listSpec, getSpec, delSpec, addSpec, updateSpec, exportSpec } from "@/api/winery/spec";
|
||||
import { listSpec, getSpec, delSpec, addSpec, updateSpec, exportSpec } from "@/api/goods/goods_spec";
|
||||
import UploadImage from '@/components/UploadImage';
|
||||
import CommonMixin from "@/mixin/common";
|
||||
|
||||
export default {
|
||||
name: "Spec",
|
||||
name: "GoodsSpec",
|
||||
mixins:[CommonMixin],
|
||||
components: {
|
||||
UploadImage
|
||||
},
|
||||
data() {
|
||||
return {
|
||||
@ -292,6 +303,9 @@ export default {
|
||||
this.$refs["form"].validate(valid => {
|
||||
if (valid) {
|
||||
if (this.form.id != null) {
|
||||
|
||||
|
||||
|
||||
updateSpec(this.form).then(response => {
|
||||
this.msgSuccess("修改成功");
|
||||
this.open = false;
|
@ -415,8 +415,6 @@ export default {
|
||||
})
|
||||
},
|
||||
onChangeNewsBody(value) {
|
||||
|
||||
console.log(value)
|
||||
this.form.newsBody = value.html
|
||||
}
|
||||
}
|
||||
|
Loading…
x
Reference in New Issue
Block a user