【odoo18-文件管理】在uniapp上访问odoo系统上的图片

打印 上一主题 下一主题

主题 900|帖子 900|积分 2700

在uniapp上访问odoo系统上的图片

  1、以url的情势访问
a:以odoo自己的域名,好比http://127.0.0.1:8069/web/image/product.template/3/image_128?unique=1740380422000,这种方式需要解决跨域的问题。

  b:以文件服务器的情势,好比http://111.229.103.209/files/

2、odoo以Base64格式返回给uniapp,使用 Vue 的数据绑定来动态更新 src 属性。Base64 编码的图片会增大数据体积(约莫增加 33%),对于大图片或大量图片,大概会影响性能和加载时间。
  1. <template>
  2.   <view>
  3.     <image :src="dynamicBase64Image" style="width: 100px; height: 100px;"></image>
  4.   </view>
  5. </template>
  6. <script>
  7. export default {
  8.   data() {
  9.     return {
  10.       dynamicBase64Image: ''
  11.     };
  12.   },
  13.   methods: {
  14.     fetchBase64Image() {
  15.       // 假设这里通过 API 获取 Base64 编码的图片
  16.       uni.request({
  17.         url: 'https://example.com/api/get-base64-image',
  18.         success: (res) => {
  19.           this.dynamicBase64Image = res.data.base64Image;
  20.         }
  21.       });
  22.     }
  23.   },
  24.   onLoad() {
  25.     this.fetchBase64Image();
  26.   }
  27. };
  28. </script>
复制代码
最终选择了以文件服务器的情势来访问。
服务器环境:腾讯云服务器ubuntu22.04
  1.使用 Nginx 托管静态文件

  1.1.nginx安装

  1. sudo apt-get install nginx # 安装nginx
  2. sudo service nginx restart # 重启nginx
复制代码
1.2.nginx环境配置

  1. cd /etc/nginx/ # 进入nginx目录,可以通过ls查看有哪些文件
  2. cd sites-available # 进入sites-available
  3. # 备份一个default
  4. sudo cp default default.bak
  5. sudo vim default
复制代码
此中location /files就是文件共享目次
  1. server {
  2.     listen 80;
  3.     server_name 111.229.103.209;  # 你的域名或服务器IP
  4.     # 静态文件托管目录
  5.     location /files {
  6.         alias /etc/odoo/filestore;  # 你的文件存储路径
  7.         autoindex on;          # 可选:开启目录浏览
  8.     }
  9.     location / {
  10.         proxy_redirect     off;
  11.         proxy_set_header   Host             $host;
  12.         proxy_set_header   X-Real-IP        $remote_addr;
  13.         proxy_set_header   X-Forwarded-For  $proxy_add_x_forwarded_for;
  14.         proxy_set_header   X-Forwarded-Proto $scheme;
  15.         proxy_read_timeout 900;  # 根据需要调整超时时间
  16.         proxy_connect_timeout 900;  # 根据需要调整超时时间
  17.         proxy_pass         http://127.0.0.1:8069;  # Odoo的默认端口是8069
  18.     }
  19.     location /longpolling {
  20.         proxy_redirect     off;
  21.         proxy_set_header   Host             $host;
  22.         proxy_set_header   X-Real-IP        $remote_addr;
  23.         proxy_set_header   X-Forwarded-For  $proxy_add_x_forwarded_for;
  24.         proxy_set_header   X-Forwarded-Proto $scheme;
  25.         proxy_read_timeout 36000s;  # 长轮询可能需要较长的超时时间
  26.         proxy_pass         http://127.0.0.1:8072;  # Odoo的长轮询端口通常是8072
  27.     }
  28.     # 如果需要HTTPS,请添加SSL配置段(略)
  29. }
复制代码
1.3.文件效果

  


  2.odoo对静态文件的读写

  2.1.odoo之ir.attachment

  以产物图片为例:

odoo的ir.attachment有3层结构,这里的文件是图片。
1、文件自己对应了一个附件,用于存储文件自己,对于相同的文件,checksum和store_fname是相同的。
2、文件对应了一个webp附件,用于文件的附件地址。
3、产物图片,好比image_1920指向了文件的地址。对于image_1920、……、image_128,假如图片较小,odoo不会压缩图片,都会对应同一张图片;假如文件较大,odoo会根据尺寸限制压缩图片,不同尺寸的image会指向不同的图片地址。

  2.2.静态文件的读写

  1. # -*- coding: utf-8 -*-
  2. import os
  3. import base64
  4. import binascii
  5. import urllib.parse
  6. from odoo import api, fields, models, _, _lt
  7. from odoo.exceptions import UserError
  8. import logging
  9. _logger = logging.getLogger(__name__)
  10. class IrAttachment(models.AbstractModel):
  11.     _inherit = 'ir.attachment'
  12.     attachment_url = fields.Char('Attachment URL', help="The URL of the file in the remote server")
  13.     def _is_image_mimetype(self):
  14.         """判断是否为图片类型"""
  15.         return self.mimetype and (self.mimetype == 'image/jpeg' or self.mimetype == 'image/png')
  16.         # return True
  17.     def _sync_image_to_nginx(self, datas, filename):
  18.         """同步图片到Nginx目录"""
  19.         nginx_dir = self.env['ir.config_parameter'].sudo().get_param('attachment.dir', '/etc/odoo/filestore')
  20.         # 获取数据库名(替换非法字符)
  21.         # nginx_dir = odoo.tools.config['data_dir']
  22.         db_name = self.env.cr.dbname.replace('/', '_').replace('\\', '_')
  23.         # 获取模型名(替换点号为下划线)
  24.         nginx_dir += f'/{db_name}/files/'
  25.         base_url = self.env['ir.config_parameter'].sudo().get_param('web.base.url')
  26.         url_parse = urllib.parse.urlparse(base_url)
  27.         attachment_url = url_parse.scheme + '://' + url_parse.hostname + f'/{db_name}/files/'
  28.         if not os.path.exists(nginx_dir):
  29.             os.makedirs(nginx_dir, exist_ok=True)
  30.             os.chmod(nginx_dir, 0o755)  # 确保目录权限
  31.         file_path = os.path.join(nginx_dir, filename)
  32.         try:
  33.             with open(file_path, 'wb') as f:
  34.                 f.write(datas)
  35.             _logger.info(f"图片已同步到Nginx目录: {file_path}")
  36.             return attachment_url
  37.         except Exception as e:
  38.             _logger.error(f"同步失败: {str(e)}")
  39.             return False
  40.     @api.model_create_multi
  41.     def create(self, vals_list):
  42.         res_ids = super().create(vals_list)
  43.         for index in range(len(res_ids)):
  44.             vals = vals_list[index]
  45.             res_id = res_ids[index]
  46.             description = vals.get('description', '')
  47.             if not res_id.mimetype or not res_id.mimetype.startswith('image') or (description and description.startswith('resize')):
  48.                 continue
  49.             store_fname = res_id.store_fname
  50.             attachment_id = self.env['ir.attachment']
  51.             if store_fname:
  52.                 attachment_id = self.env['ir.attachment'].search([
  53.                     ('id', '!=', res_id.id),
  54.                     ('res_model', '=', 'ir.attachment'),
  55.                     ('store_fname', '=', store_fname),
  56.                 ])
  57.             if attachment_id and attachment_id.attachment_url:
  58.                 res_id.write({
  59.                     'attachment_url': attachment_id.attachment_url
  60.                 })
  61.                 continue
  62.             if not res_id._is_image_mimetype():
  63.                 continue
  64.             if not vals.get('res_id'):
  65.                 continue
  66.             attachment_id = self.env['ir.attachment'].sudo().browse(vals.get('res_id'))
  67.             datas = vals.get('datas')
  68.             if not datas or not attachment_id:
  69.                 continue
  70.             # Base64解码
  71.             file_data = base64.b64decode(datas) or False
  72.             # 同步到Nginx
  73.             filename = "%s_%s" % (store_fname.replace('/', '_').replace('\\', '_'), vals.get('name'))
  74.             attachment_url = self._sync_image_to_nginx(file_data, filename)
  75.             if attachment_url:
  76.                 attachment_id.write({'attachment_url': attachment_url})
  77.         return res_ids
  78.     def unlink(self):
  79.         """删除时同步清理static文件"""
  80.         for attach in self:
  81.             if attach.attachment_url and os.path.exists(attach.attachment_url):
  82.                 try:
  83.                     os.remove(attach.attachment_url)
  84.                     # 尝试清理空目录
  85.                     dir_path = os.path.dirname(attach.attachment_url)
  86.                     if not os.listdir(dir_path):
  87.                         os.rmdir(dir_path)
  88.                     _logger.info(f"已删除: {attach.attachment_url}")
  89.                 except Exception as e:
  90.                     _logger.error(f"删除失败: {str(e)}")
  91.         return super().unlink()
  92.     def write(self, vals):
  93.         try:
  94.             bin_data = base64.b64decode(vals.get('datas', '')) or False
  95.         except binascii.Error:
  96.             raise UserError(_("Attachment is not encoded in base64."))
  97.         if self.mimetype and self.mimetype.startswith('image'):
  98.             checksum = self._compute_checksum(bin_data)
  99.             attachment_id = self.env['ir.attachment'].search([
  100.                 ('id', '!=', self.id),
  101.                 ('res_model', '=', 'ir.attachment'),
  102.                 ('checksum', '=', checksum),
  103.             ])
  104.             if attachment_id and attachment_id.attachment_url:
  105.                 vals['attachment_url'] = attachment_id.attachment_url
  106.         return super(IrAttachment, self).write(vals)
复制代码


  2.3.静态文件的获取和表现

  1. # -*- coding: utf-8 -*-
  2. import json
  3. import logging
  4. from odoo.http import Controller, request, route
  5. class ProductController(Controller):
  6.     @route(['/api/product/list'], type='http', auth='public', methods=['GET', 'OPTIONS'], csrf=False, cors='*')
  7.     def api_product_list(self, **kw):
  8.         logging.info('api_product_list:%s', kw)
  9.         product_ids = request.env['product.product'].sudo().search([])
  10.         data = []
  11.         for product_id in product_ids:
  12.             domain = [
  13.                 ('res_model', '=', 'product.template'),
  14.                 ('res_field', '=', 'image_1920'),
  15.                 ('res_id', 'in', product_id.product_tmpl_id.id),
  16.             ]
  17.             attachment_id = request.env['ir.attachment'].sudo().search(domain)
  18.             data.append({
  19.                 'id': product_id.id,
  20.                 'name': product_id.name,
  21.                 'lst_price': product_id.lst_price,
  22.                 'thumbnail': attachment_id.attachment_url
  23.             })
  24.         return json.dumps({'code': 200, 'data': data, 'count': len(product_ids)})
复制代码


  3.总结

  nginx静态文件的方式可以扩展到系统日记、备份等需要保存文件的场景。

免责声明:如果侵犯了您的权益,请联系站长,我们会及时删除侵权内容,谢谢合作! 更多信息从访问主页:qidao123.com:ToB企服之家,中国第一个企服评测及商务社交产业平台。

本帖子中包含更多资源

您需要 登录 才可以下载或查看,没有账号?立即注册

x
回复

使用道具 举报

0 个回复

倒序浏览

快速回复

您需要登录后才可以回帖 登录 or 立即注册

本版积分规则

傲渊山岳

金牌会员
这个人很懒什么都没写!

标签云

快速回复 返回顶部 返回列表